url动态加解密
表单提交(或其他需要请求后台url)的场景下,url对于客户端来说是可见的,攻击者可以通过url猜测到很多信息并伪造请求对url进行攻击。本文探讨了一种对
url加密和解密的方案,并给出了关键代码。
Form表单提交
页面form的action地址加密:
先在原始url之前添加
encoded/
(或其他)以方便后台认证是否合法url;
在加密后的url地址后加.do
(或其他)以方便filter过滤。1
2
3
4
5
6
7
8
9
10<%
String url = DesUtil.encrypt("encoded/test/second.htm");
%>
<form action="<%=url%>.do" method="post">
<input type="text" id="account" name="j_username" class="text " placeholder="请输入手机号/邮箱"
value="tangliu"/>
<input type="text" id="password" name="j_password" class="text " placeholder="请输入密码"
value="123456"/>
<input type="submit" value="Submit" />
</form>自定义一个filter,放在其他filter之前:
1
2
3
4
5
6
7
8
9<filter>
<filter-name>decodeFilter</filter-name>
<filter-class>com.tangliu.test.encodeurl.DecodeUrlFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>decodeFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>filter中对url进行解密,若解密后的url不符合规范(不是以”encoded/“开头),则抛弃,否则对url请求进行forward转发。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
try {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String encodedUrl = httpRequest.getRequestURI();
encodedUrl = encodedUrl.substring(1, (encodedUrl.length() - 3));
String unencodedUrl = DesUtil.decrypt(encodedUrl);
//如果解密后不是以encoded开头则说明不是合法请求,抛弃
if(!unencodedUrl.startsWith("encoded"))
return;
unencodedUrl = unencodedUrl.replace("encoded/", "");
unencodedUrl = httpRequest.getContextPath() + unencodedUrl;
request.getRequestDispatcher("/" + unencodedUrl).forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}经过测试,froward转发的url可以被其他filter正确拦截,于此同时地址栏显示的是加密后的url,设置如下:
1
2
3
4
5
6
7
8
9
10
11<filter>
<filter-name>testFilter</filter-name>
<filter-class>com.tangliu.test.encodeurl.TestFilter</filter-class>
<async-supported>true</async-supported>
</filter>
<filter-mapping>
<filter-name>testFilter</filter-name>
<url-pattern>/test/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>其中
<dispatcher>
标签如果不设置,默认是REQUEST,表示拦截客户端请求,FORWARD
表示拦截内部的forward请求。同时最后收到请求的controller,能够正常接收request的参数:
1
2
3
4
5
6
7
8
9@RequestMapping(value = "second", method = RequestMethod.POST)
@ResponseBody
public String service(HttpServletRequest request) {
System.out.println(request.getParameter("j_username"));
System.out.println(request.getParameter("j_password"));
return "test";
}
使用ajax post提交
在
<meta>
中写入加密后的url地址:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<meta name="formUrl" content="<%=DesUtil.encrypt("encoded/test/second.htm")%>.do">
<script src="//cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<script>
function ajaxTest(){
var url = $("meta[name='formUrl']").attr("content");
var data = {};
data['j_username'] = 'tangliu';
data['j_password'] = '123456';
$.post(url, data, function(result){
alert(result);
});
}
</script>在
<script>
中写入加密后的url地址:1
2
3
4
5
6
7
8
9
10
11
12<script>
function ajaxTest(){
var url = "<%=DesUtil.encrypt("encoded/test/second.htm")%>.do";
var data = {};
data['j_username'] = 'tangliu';
data['j_password'] = '123456';
$.post(url, data, function(result){
alert(result);
});
}
</script>
测试可行。