如何区分String中的两个字符串?(如何防止纯文本注入)

时间:2013-09-10 15:24:08

标签: java string code-injection

假设我有两个随机生成的字符串。

如何生成一个包含两个字符串的字符串,同时能够将它们拆分成原始的两个字符串供以后使用?

例如,我有“[aweiroj \ 3aoierjvg0_3409”和“4093 w_ / e9”。如何将这两个单词附加到一个变量中,同时能够将它们拆分为原始的两个字符串?

我的问题是,我似乎找不到.spit()的正则表达式,因为这两个字符串可以有任何字符(alpabet,整数,\,/,空格......)。

修改

我只想到了一个可以使用它的真实案例。 Sometimes,通过网络(HTTP)发送纯文本比xml或json更好。宽带速度慢的服务器 - 使用xml或json,宽带慢速的快速服务器 - 使用纯文本。以下答案可能会阻止纯文本注入。但是,这些方法没有进行基准测试或测试,我可能会在实际使用它们之前测试这些方法。

4 个答案:

答案 0 :(得分:9)

简短的回答是:不要这样做。使用数组或具有两个数据成员的类,但将字符串组合成一个字符串可能是一个坏主意。

但如果你有一些真正模糊的用例,你可以:

  1. 创建一个足够独特的分隔符,例如"<<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. 如果字符串中存在,您可以使用更简单的分隔符。

  3. 记住第一个字符串的长度并将其存储在统一字符串中,后跟“end of length”分隔符。

    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);
    
  4. (两个代码示例都完全袖手旁观,未经测试。)

答案 1 :(得分:4)

我会创建一个包含两个字符串的类,并且能够将它们分开打印并组合在一起。

这个只是扩展了ArrayList,因此您无需重新实现addget等等:

public class ConcatedString extends ArrayList<String>
{

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

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

        return b.toString();
    }
}

答案 2 :(得分:3)

如果这是一些(模糊)类型的序列化问题,那么至少有一种明显的方法可以做到这一点。

使用某种编码对字符串进行编码(HTML编码是一种简单易读的选择)。选择编码字符串不可能包含的字符,将其用作分隔符并将它们连接起来。

然后,要检索,按字符分隔字符串并使用初始方法反向解码子字符串。

答案 3 :(得分:2)

如果您希望它在每种情况下都有效,则需要定义2个特殊字符:

  • 分隔符
  • 逃脱角色。

1-Encoding:当您连接2个字符串时:

在两个字符串中,

  • 将所有等于转义字符的字符替换为2 转义字符
  • 转义 + 分隔符
  • 替换所有等于分隔符字符的字符

然后将两个String与它们之间的分隔符字符连接起来。

2-Decoding:解码字符串时:

  • 如果当前字符是转义字符,而下一个字符也是转义字符,请将其替换为仅一个转义字符,跳过1个字符。
  • 如果当前字符是转义字符,而下一个字符也是分隔符字符,请将其替换为仅一个分隔符字符,跳过1个字符。
  • 如果当前字符是分隔符字符,则表示您处于2个原始字符串之间。

这是一个有效的例子:

//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()};
}

测试:

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))));
  }
}

输出:

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

另一种方式,使用以下格式格式化编码的字符串:

size_of_str_1:str1|size_of_str2:str2

示例:如果string1为'aa'且string2为'bbbb',则编码的String为:'2:aa | 4:bbbb'。

通过String #subString()解码它。 “硬”部分是解析字符串,直到你完成读取下一个字符串的大小。