How to distinguish two strings in a String?(How to prevent plain text injection)

让人想犯罪 __ 提交于 2020-01-03 05:17:33

问题


Say I have two randomly generated Strings.

What can I do to make a single String with the two Strings generated, while being able to split them to get the original two Strings for later use?

For example, I have "[aweiroj\3aoierjvg0_3409" and " 4093 w_/e9 ". How can I attach those two words into one variable while being able to split them to original two Strings?

My problem is, I can't seem to find a regex for .spit() because those two strings can have any chararacters(alpabet, integer, \, /, spaces...).

EDIT

I just thought of a real life case where this could be used. Sometimes, sending plain text over network(HTTP) is better than xml or json. Slow server with fast broadband - use xml or json, fast server with slow broadband - use plain text. The answers below could prevent plain text injection. However, these methods are not benchmarked or tested, I would probably test these methods before actually using them.


回答1:


The short answer is: Don't do that. Use an array, or a class with two data members, but combining the strings together into one string is probably a bad idea.

But if you have some truly obscure use case, you can:

  1. Create a sufficiently-unique delimiter, like "<<Jee Seok Yoon's Delimiter>>".

    final static String DELIM = "<<Jee Seok Yoon's Unique Delimiter>>";
    String a = /*...*/;
    String b = /*...*/;
    String combined = a + DELIM + b;
    
    int breakAt = combined.indexOf(DELIM);
    String a1 = combined.substring(0, breakAt);
    String b1 = combined.substring(breakAt + DELIM.length());
    
  2. Have a simpler delimiter that you escape if present in the string.

  3. Remember the length of the first string and store it in your unified string followed by an "end of length" delimiter.

    String a = /*...*/;
    String b = /*...*/;
    String combined = String.valueOf(a.length()) + "|" + a + b;
    
    int breakAt = combined.indexOf("|");
    int len = Integer.parseInt(combined.substring(0, breakAt), 10);
    String a1 = combined.substring(breakAt + 1, len);
    String b1 = combined.substring(breakAt + 1 + len);
    

(Both code examples are completely off-the-cuff and untested.)




回答2:


I would create a Class that holds both Strings and is able to print them seperatly and combined.

This one simply extends ArrayList so you don't need to reimplement add, get and so on:

public class ConcatedString extends ArrayList<String>
{

    public String concated() {
        StringBuilder b = new StringBuilder();

        for (String string : this)
        {
            b.append(string);
        }

        return b.toString();
    }
}



回答3:


If this is a matter of serialization of some (obscure) kind, then there is at least one obvious way to do this.

Encode the strings using some encoding (HTML encoding is an easy and readable choice). Pick a character that the encoded strings cannot possibly contain, use that as a separator and concatenate them all.

Then, to retrieve, separate the strings by that character and decode the substrings using your initial method in reverse.




回答4:


If you want it to work in every cases, you need to define 2 special characters :

  • A delimiter character
  • An escape character.

1-Encoding : When you concat the 2 String :

In both String,

  • replace all characters which equal the escape character with 2 escape characters
  • replace all characters which equal the delimiter character with escape + delimiter

then concat both String with the delimiter character between them.

2-Decoding : When you decode the String :

  • If the current character is a escape character while the next one is also a escape character, replace it with only one escape character and skip 1 character.
  • If the current character is a escape character while the next one is also a delimiter character, replace it with only one delimiter character and skip 1 character.
  • If the current character is the delimiter character, then you are between the 2 original Strings.

Here is a working example :

//I make on purpose a bad choice for escape/delimiter characters
private static final char DELIMITER = '1';
private static final char ESCAPE = '2';

public static String encode(String s1, String s2){
  StringBuilder sb = new StringBuilder();

  subEncode(s1, sb);

  sb.append(DELIMITER);

  subEncode(s2, sb);

  return sb.toString();
}

private static void subEncode(String s, StringBuilder sb) {
  for(char c : s.toCharArray()) {
    if(c == ESCAPE) {
      sb.append(ESCAPE);
      sb.append(ESCAPE);
    }else if(c == DELIMITER) {
      sb.append(ESCAPE);
      sb.append(DELIMITER);
    }else {
      sb.append(c);
    }
  }
}

public static String[] decode(String encoded) {
  StringBuilder sb1 = new StringBuilder();
  StringBuilder sb2 = new StringBuilder();

  StringBuilder currentSb = sb1;
  char[] chars = encoded.toCharArray();
  for(int i = 0; i< chars.length ; i++) {

    if(chars[i] == ESCAPE) {
      if(chars.length < i+2) {
        throw new IllegalArgumentException("Malformed encoded String");
      }
      if(chars[i+1] == ESCAPE) {
        currentSb.append(ESCAPE);

      }else if(chars[i+1] == DELIMITER) {
        currentSb.append(DELIMITER);
      }
      i++;
    }else if(chars[i] == DELIMITER) {
      currentSb=sb2;
    }else {
      currentSb.append(chars[i]);
    }
  }
  return new String[]{sb1.toString(), sb2.toString()};
}

Test :

public static void main(String[] args) {
  //Nominal case :
  {
  String s1 = "aaa";
  String s2 = "bbb";
  System.out.println("Encoded : " + encode(s1, s2));
  System.out.println("Decoded" + Arrays.asList(decode(encode(s1,s2))));
  }

  //with bad characters :
  {
  String s1 = "111";
  String s2 = "222";
  System.out.println("Encoded : " + encode(s1, s2));
  System.out.println("Decoded" + Arrays.asList(decode(encode(s1,s2))));
  }

  //with random characters :
  {
    String s1 = "a11a1";
    String s2 = "1112bb22";
    System.out.println("Encoded : " + encode(s1, s2));
    System.out.println("Decoded" + Arrays.asList(decode(encode(s1,s2))));
  }
}

Output :

Encoded : aaa1bbb
Decoded[aaa, bbb]
Encoded : 2121211222222
Decoded[111, 222]
Encoded : a2121a21121212122bb2222
Decoded[a11a1, 1112bb22]

Another way to do this, format the encoded String using the following format :

size_of_str_1:str1|size_of_str2:str2

Example : if string1 is 'aa' and string2 is 'bbbb', the encoded String is : '2:aa|4:bbbb'.

You decode it via String#subString(). the "hard" part is to parse the string until you finished to read the size of the next String.



来源:https://stackoverflow.com/questions/18722911/how-to-distinguish-two-strings-in-a-stringhow-to-prevent-plain-text-injection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!