-3

I have a byte[] that contains the HTTP request body. In the body I want to remove the password information before logging the whole body. I can remove the password information if I first convert the byte[] to string but as I know it is never a good idea to convert a password to string (because the password will be stored in the string pool and as such it is a security concern).

The content of the byte[] is something like (but it can change): body: [{"email":"email@email.com","password":"some_password",.....}]

So how can I remove the "password":"some_password"part from the byte[] without first converting it to a string?

Elio
  • 428
  • 3
  • 20

2 Answers2

2

I can remove the password information if I first convert the byte[] to string.

I don't understand why you think that. if you want to remove the password information, just update the cells of the byte[] that contain the password characters. For example

  for (int i = start_of_password; i < end_of_password; i++) {
      bytes[i] = 'X';
  }

And if you do need to extract the password from the byte[] you can put the characters into another byte[] ... which you can then erase after use.

... but as I know it is never a good idea to convert a password to string (because the password will be stored in the string pool and as such it is a security concern).

When you create a Java String from some bytes (or by calling new String(other_string)), this does NOT put the resulting string into the string pool. The string you just created is an ordinary heap object. Unless your application keeps the reference somewhere it is liable to be eligible for garbage collection pretty quickly.

There are only two circumstances where a String goes into the string pool:

  • when the String corresponds to a string literal (or "constant expression") in the source code, or

  • when something explicitly calls intern() on the String object.

The other thing to consider is why a long-lived String in memory could be considered to be a security issue. The problem is that there is a risk a "bad guy" could get hold of the password. There are a few potential scenarios:

  1. If someone was able to compromise the JVM and inject bad code into it (for JVM or application security flaw) then they might be able to extract strings. It would be really hard to achieve though. It requires a lot of knowledge of the application and the framework that is running it In fact, it be just as easy to extract the password from a byte[]. Anyway, the remedy for this is to keep your JVM up to date, and audit your codebase for overt security problems that could lead to a JVM hack.

  2. If someone can get root access, they can use this to read the memory of any process. In the simple case, they can get a core dump of the entire process. But if they can do that, they could also stealthily modify your application or the framework to log passwords and exfiltrate them. The remedy for this is getting your system security and procedures up to scratch.

  3. If someone can get physical access to your server, they could steal the dard drives and recover a partial copy of JVM memory from the swap region. The remedy for this is to implement proper physical security for your servers.

Now all of these attacks are plausible, but in each case there are either a simple mitigation ... or a simple way to defeat the "no passwords in strings" precaution. I would advise taking the other measures before dealing with this concern.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Thnx for explaining the security issues. It is just a security policy that we follow in team. You can see also a relevant post here: https://stackoverflow.com/questions/8881291/why-is-char-preferred-over-string-for-passwords . Now I have an other question to your solution. How do I find start_of_password and end_of_password? That is exactly what I don't know. How do I locate the position of a string in a byte[]? – Elio Mar 18 '20 at 08:37
  • Basically with a byte-wise loop and some tests simple tests. The details will depend on how the password is encoded in the request buffer. It will be a bit messy and *ad hoc*. – Stephen C Mar 18 '20 at 09:00
0

As I interpret your code, the byte array contains the keywords body, email, and password. So you can check if the bytes of the keywords do not change between different samples of byte arrays and if they do not change then you remove everything after the bytes of the password keyword. If you have another keyword after the password, then you just remove everything until this keyword.

Here is an example, how it could look like:

import java.util.ArrayList;

public class MyClass {
    public static void main(String args[]) {
      byte a[] = "body: [{\"email\":\"email@email.com\",\"password\":\"some_password\",.....}]".getBytes();
      byte[] pass = {34,112,97,115,115,119,111,114,100,34,58,34};  //"\"password\":\"".getBytes();
      byte[] end = {34,44}; //"\",".getBytes();
      ArrayList<Byte> arrList= new ArrayList<Byte>();
      boolean foundPassword = false;
      for(int i=0;i<a.length;i++){
        if (a[i] == pass[0] && a[i+1] == pass[1] && a[i+2] == pass[2] && a[i+3] == pass[3] && a[i+4] == pass[4] && a[i+5] == pass[5] && a[i+6] == pass[6] && a[i+7] == pass[7] && a[i+8] == pass[8] && a[i+9] == pass[9] && a[i+10] == pass[10] && a[i+11] == pass[11]){
            i = i+12;
            foundPassword = true;
        } else if (!foundPassword){
            arrList.add(a[i]);
        } else if (foundPassword && a[i] == end[0] && a[i+1] == end[1]){
            arrList.add(new Integer(44).byteValue());
            foundPassword = false;
            i+2;
        }
      }

      byte[] result = new byte[arrList.size()];
      for(int i=0;i<arrList.size();i++)
            result[i] = arrList.get(i);

      System.out.println(new String(result));


    }
}

Output: body: [{"email":"email@email.com",,.....}]

Leonid Glanz
  • 1,261
  • 2
  • 16
  • 36
  • Actually what I need to to, is to locate the this `"password":"some_password"` in the byte array and remove it. But I don't know how. – Elio Mar 18 '20 at 08:47
  • Could you please represent the byte array content as Java String? It would help me to understand the underlying format of such byte arrays. – Leonid Glanz Mar 18 '20 at 09:32
  • Yes it looks like a JSON format: [{"email":"email@email.com","password":"some_password",.....}] . You can see it also in my original post. – Elio Mar 18 '20 at 09:51
  • I have added an example, how you could work on a byte array without transforming the array into a string. The end statement is just to show the result. – Leonid Glanz Mar 18 '20 at 10:25
  • It is that what I was looking for. It is complicated but I will test it and let you know. Thnx. – Elio Mar 18 '20 at 10:50