通过SpringBoot搭建restful API服务,使用JWT进行登录验证,客户端每次登录会重新获取token,发现API服务端过滤器AuthFilter,通过HTTP 请求头获取token并验证token时,偶尔会报:io.jsonwebtoken.SignatureException:
JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
因为每次重新登录(新token)后又正常了,所以项目运行了半年多,也没去管它。今日再查OOM问题时,发现日志很多这个JWT错误,遂萌生了要彻底解决此问题的想法,恰巧开发环境刚好又报了这个错,通过调试发现客户端通过HTTP请求时,把token放到request header中,到达 API服务器端解析时,拿到的token中含有的特殊字符--不见了,所以报:JWT signature does not match locally computed signature
原因是用自定义的工具类HttpKit.getRequest()获取request对象,得到参数token时,这个自定义的工具类里对HttpServletRequest获取的参数做了特殊字符过滤,所以token里如果有“--”这样的字符就会被过滤掉,导致token验证失败。
解决方案:通过Debug模式,跟踪客户端传到服务器端token值的变化,如果是我这种情况,想办法直接从HttpServletRequest 对象获取token就可以了。
HttpKit.getRequest()工具类里对特殊字符过滤的方法如下:
public static String stripXSS(String value) { String rlt = null; if (null != value) { // NOTE: It's highly recommended to use the ESAPI library and uncomment the following line to // avoid encoded attacks. // value = ESAPI.encoder().canonicalize(value); // Avoid null characters rlt = value.replaceAll("", ""); // Avoid anything between script tags Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE); rlt = scriptPattern.matcher(rlt).replaceAll(""); // Avoid anything in a src='...' type of expression /*scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); rlt = scriptPattern.matcher(rlt).replaceAll(""); scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); rlt = scriptPattern.matcher(rlt).replaceAll("");*/ // Remove any lonesome </script> tag scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE); rlt = scriptPattern.matcher(rlt).replaceAll(""); // Remove any lonesome <script ...> tag scriptPattern = Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); rlt = scriptPattern.matcher(rlt).replaceAll(""); // Avoid eval(...) expressions scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); rlt = scriptPattern.matcher(rlt).replaceAll(""); // Avoid expression(...) expressions scriptPattern = Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); rlt = scriptPattern.matcher(rlt).replaceAll(""); // Avoid javascript:... expressions scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE); rlt = scriptPattern.matcher(rlt).replaceAll(""); // Avoid vbscript:... expressions scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE); rlt = scriptPattern.matcher(rlt).replaceAll(""); // Avoid οnlοad= expressions scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); rlt = scriptPattern.matcher(rlt).replaceAll(""); } return rlt; }