【问题标题】:is it safe to use string hashcode as etag使用字符串哈希码作为 etag 是否安全
【发布时间】:2015-05-11 15:30:45
【问题描述】:

给定一个特定的输入参数,对于一个 rest api,我想使用哈希码作为 etag。 json响应发生变化而hashcode不变的概率是多少?

或者有没有更好的方法来做到这一点?

@GET
    public Response getConfigurationForView(@PathParam("in1") String in1, @Context Request request) throws Exception {
        String jsonResponse = getJsonResponse(in1);
        EntityTag etag = new EntityTag(Integer.toString(in1.hashCode()) + "-" + Integer.toString(jsonResponse.hashCode()));
        ResponseBuilder builder = request.evaluatePreconditions(etag);


         if(builder == null){
             builder = Response.ok(jsonResponse, MediaType.APPLICATION_JSON);
             builder.tag(etag);
         }

        return builder.build();
    }

【问题讨论】:

  • 据我了解,引用的帖子是关于字符串的哈希码是否在不同版本的 java 中相同。我在问,对于两个不同的字符串,我会得到相同的哈希码的概率是多少。
  • 注意:hashcode 可以是负数。有时字符串不应包含连字符。

标签: java jersey probability


【解决方案1】:

鉴于您对于各种字符串只有 40 亿个可能的哈希码,您很有可能最终会遇到 ETag 冲突。

看看String.hashCode()是如何实现的:

        char val[] = value;

        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;

-- 你甚至可以自己想出可能的碰撞。例如,""(一个空字符串)和"\0"(仅包含\0 字符的字符串)将为您提供相同的hashCode 0。

我建议您使用 SHA1 哈希(或 MD5,但请先查看 securityCPU running time 上的这些注释)。

如果您继续使用 SHA1 哈希,您的代码可能如下所示:

public static String calculateEtag(final String s) throws java.security.NoSuchAlgorithmException {
    final java.nio.ByteBuffer buf = java.nio.charset.StandardCharsets.UTF_8.encode(s);
    final java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA1");
    buf.mark();
    digest.update(buf);
    buf.reset();
    return String.format("W/\"%s\"", javax.xml.bind.DatatypeConverter.printHexBinary(digest.digest()));
}

这将产生与sha1sum 实用程序相同的输出。 您也可以使用BigInteger 将字节缓冲区转换为十六进制字符串:

new BigInteger(1, digest.digest()).toString(16)

-- 但javax.xml.bind.DatatypeConverter.printHexBinary() 快几倍。

【讨论】:

【解决方案2】:

如果你可以使用 jdk8+ 和 Google Guava,你可以试试

final String myETag = ( (Set<Object>) this.setOfChangeableProperties ).stream()
  .filter( Objects::nonNull )
  .map( Objects::toString )
  .reduce( (a,b) -> a.concat(b) )
  .map( s -> Hashing.md5().hashUnencodedChars( s ).toString() )
  .orElse( "nothing of interest to hash!" )

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-10
    • 2020-03-30
    • 1970-01-01
    • 2019-08-08
    • 1970-01-01
    • 1970-01-01
    • 2013-04-24
    • 2019-12-03
    相关资源
    最近更新 更多