IBM AppScan安全扫描:加密会话(SSL)Cookie中缺少Secure 属性处理办法
原因分析:
服务器开启了Https时,cookie的Secure属性应设为true;
解决办法:
1.服务器配置Https SSL方式,参考:https://support.microsoft.com/kb/324069/zh-cn
2.修改web.config,添加:
<system.web>
<httpCookieshttpOnlyCookies="true" requireSSL="true" />
<system.web>
See:http://msdn.microsoft.com/en-us/library/ms228262(v=vs.100).aspx
3.修改后台写Cookies时的设置 cookie.Secure = true:
HttpResponse response= HttpContext.Current.Response;
var cookie = new HttpCookie(key, value);
cookie.HttpOnly = true;
cookie.Path = "/";
cookie.Expires = DateTime.Now.AddHours(1);
cookie.Secure = true;
response.AppendCookie(cookie);
参考网站:http://stackoverflow.com/questions/5978667/how-to-secure-the-asp-net-sessionid-cookie
解决方法:
1.Server 2008(R2)
根据appScan的修订建议访问地址:http://msdn.microsoft.com/en-us/library/windows/desktop/bb870930(v=vs.85).aspx
里面说了如何修改SSL 密码套件的优先级和状态,里面有一堆的加密方式,很难知道哪些该保留,哪些改去掉(其实AppScan里面已经有提示哪些该去掉);
经过一番资料查找,有一个名叫IIS Crypto的软件工具,专门用来解决上面的问题;
软件地址:https://www.nartac.com/Products/IISCrypto/Default.aspx
运行软件设置他推荐的加密方式,然后重启系统,再次扫描时,就不会报这个漏洞了。
参考资料:
1.http://msdn.microsoft.com/en-us/library/windows/desktop/bb870930(v=vs.85).aspx
2.http://security.stackexchange.com/questions/48325/identify-and-disable-weak-cipher-suites
3.https://www.nartac.com/Products/IISCrypto/Default.aspx
CSRF(Cross-site request forgery),中文名称:跨站请求伪造.
因为这个不是用户真正想发出的请求,这就是所谓的请求伪造;因为这些请求也是可以从第三方网站提交的,所以前缀跨站二字。
CSRF发生的场景如下图所示:
用户登录访问了一个受信任的站点,
在用户还没有退出登录的时候,打开另外一个tab页,访问了网站B。
在B网站中,有CSRF攻击代码访问网站A。
发生的原因是,网站是通过cookie来识别用户的,当用户成功进行身份验证之后浏览器就会得到一个
标识其身份的cookie,只要不关闭浏览器或者退出登录,以后访问这个网站会带上这个cookie。
1.登录受信任网站A,并在本地生成Cookie。
2.在不登出A的情况下,访问危险网站B。
你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。
是的,确实如此,但你不能保证以下情况不会发生:
1.你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
2.你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。
(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于
退出登录/结束会话了)如记住密码功能等。
3.上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。
下面来看一个代码实例,在网站A发布了下面的代码
用户login,然后可以在input.jsp提交数据,提交的数据被dataupdate.jsp更新到后台。
dataupdate.jsp会检查用户是否登录,如果没有登录会跳到login.jsp要求用户登录。
1. login.jsp
2. <body>
3. <formaction="input.jsp"method="post">
4. name<inputtype="text"name="name"size="50"><br>
5. pwd<inputtype="password"name="password"size="50"><br>
6. <inputtype="submit"value="submit">
7. </form>
8. <br>
9. </body>
10.</html>
11.
12.input.jsp
13.<body>
14.<%
15.//Sessionsession=request.getSession();
16.Stringusername=(String)session.getValue("username");
17.System.out.println("username" + username);
18.if(null==username){
19.Stringuname=request.getParameter("name");
20.session.putValue("username",uname);
21.}
22.
23.%>
24.<formaction="dataupdate.jsp"method="post">
25.<inputtype="text"name="comment"size="50"><br>
26.<inputtype="submit"value="submit">
27.</form>
28.<br>
29.</body>
30.
31.dataupdate.jsp
32.<body>
33.<%
34.Stringusername=(String)session.getValue("username");
35.System.out.println("username" + username);
36.if(null==username){
37.System.out.println("hasnot logged in");
38.response.sendRedirect("login.jsp");
39.}else{
40.Stringcomment=request.getParameter("comment");
41.
42.System.out.println("adda comment: " + comment);
43.
44.out.write("commentis : " + comment);
45.}
46.%>
47.</body>
48.</html>
login.jsp
<body>
<form action="input.jsp" method="post">
name<input type="text" name="name" size="50"><br>
pwd<input type="password" name="password" size="50"><br>
<input type="submit" value="submit">
</form>
<br>
</body>
</html>
input.jsp
<body>
<%
//Session session = request.getSession();
String username = (String)session.getValue("username");
System.out.println("username " + username);
if(null==username){
String uname = request.getParameter("name");
session.putValue("username", uname);
}
%>
<form action="dataupdate.jsp" method="post">
<input type="text" name="comment" size="50"><br>
<input type="submit" value="submit">
</form>
<br>
</body>
dataupdate.jsp
<body>
<%
String username = (String)session.getValue("username");
System.out.println("username " + username);
if(null==username){
System.out.println("has not logged in");
response.sendRedirect("login.jsp");
}else{
String comment = request.getParameter("comment");
System.out.println("add a comment: " + comment);
out.write("comment is : " + comment);
}
%>
</body>
</html>
表面上看起来好像没有问题。
假设我们有另外一个网站B,它有一个网页文件如下
如果在用户登录访问网站A的同时访问了网站B,访问者在网站A的数据就会被假冒更新。
可以在后台看到有如下的输出:add a comment: fromcsrf
1. <body>
2. use a imgelement to send a get request <br>
3. <imgsrc="http://www.a.com/prjWebSec/csrf/dataupdate.jsp?comment=fromcsrf">
4. </body>
5. </html>
<body>
use a img element to send a get request <br>
<img src="http://www.a.com/prjWebSec/csrf/dataupdate.jsp?comment=fromcsrf">
</body>
</html>
这里网站A违反了HTTP规范,使用GET请求更新资源。那是不是用post请求就不会发生CSRF呢?
结果是同样会发生。可以通过构造javascript构造form提交,如下面的代码
1. <body>
2. </body>
3. <scripttype="text/javascript">
4.
5. varfrm=document.getElementById("viframe");
6. functionsendcsrf()
7. {
8. varform1=document.createElement("form");
9. form1.id= "form1";
10.form1.name= "form1";
11.document.body.appendChild(form1);
12.
13.varinput=document.createElement("input");
14.input.type= "text";
15.input.name= "comment";
16.input.value= "fromcsrf post";
17.
18.form1.appendChild(input);
19.form1.method= "POST";
20.form1.action= "http://www.a.com/prjWebSec/csrf/dataupdate.jsp";
21.form1.submit();
22.document.body.removeChild(form1);
23.}
24.sendcsrf();
25.</script>
26.</html>
<body >
</body>
<script type="text/javascript">
var frm= document.getElementById("viframe");
function sendcsrf()
{
var form1 = document.createElement("form");
form1.id = "form1";
form1.name = "form1";
document.body.appendChild(form1);
var input = document.createElement("input");
input.type = "text";
input.name = "comment";
input.value = "from csrf post";
form1.appendChild(input);
form1.method = "POST";
form1.action = "http://www.a.com/prjWebSec/csrf/dataupdate.jsp";
form1.submit();
document.body.removeChild(form1);
}
sendcsrf();
</script>
</html>
防止方法:
1,利用referer判断,
但是用户有可能设置浏览器使其在发送请求时不提供Referer,这样的用户也将不能访问网站。
2,在请求中添加token并验证
关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于cookie之中,
可以在服务器端生成一个随机码,然后放在form的hidden元素中,form提交的时候在服务器端检查。
会话标识未更新:登录页面加入以下代码
- request.getSession(true).invalidate();//清空session
- Cookie cookie = request.getCookies()[0];//获取cookie
- cookie.setMaxAge(0);//让cookie过期
request.getSession(true).invalidate();//清空session
Cookie cookie = request.getCookies()[0];//获取cookie
cookie.setMaxAge(0);//让cookie过期
不是很明白session的机制,高手路过可以指教一下。
2.跨站点请求伪造:
在出错的url加参数sessionid。
- response.getWriter().write( "<script>parent.location.href='dbase/admin/loginJsp.action?sessionId="+sessionId+"'</script>");
response.getWriter().write( "<script>parent.location.href='dbase/admin/loginJsp.action?sessionId="+sessionId+"'</script>");
如果带参数报ssl错误,使用下面的post方式传值:
- response.getWriter().write(
- "<script language=\"javascript\"> " +
- "document.write(\"<form action=dbase/admin/loginJsp.action method=post name=formx1 style='display:none'>\");" +
- "document.write(\"<input type=hidden name=name value='"+sessionId+"'\");" +
- "document.write(\"</form>\");" +
- "document.formx1.submit();" +
- "</script>"
- );
response.getWriter().write(
"<script language=\"javascript\"> " +
"document.write(\"<form action=dbase/admin/loginJsp.action method=post name=formx1 style='display:none'>\");" +
"document.write(\"<input type=hidden name=name value='"+sessionId+"'\");" +
"document.write(\"</form>\");" +
"document.formx1.submit();" +
"</script>"
);
3.启用不安全HTTP方法
Java代码
- 修改web工程中或者服务器web.xml,增加安全配置信息,禁用不必要HTTP方法
- <security-constraint>
- <web-resource-collection>
- <url-pattern>/*</url-pattern>
- <http-method>PUT</http-method>
- <http-method>DELETE</http-method>
- <http-method>HEAD</http-method>
- <http-method>OPTIONS</http-method>
- <http-method>TRACE</http-method>
- </web-resource-collection>
- <auth-constraint>
- </auth-constraint>
- </security-constraint>
- <login-config>
- <auth-method>BASIC</auth-method>
- </login-config>
修改web工程中或者服务器web.xml,增加安全配置信息,禁用不必要HTTP方法
<security-constraint>
<web-resource-collection>
<url-pattern>/*</url-pattern>
<http-method>PUT</http-method>
<http-method>DELETE</http-method>
<http-method>HEAD</http-method>
<http-method>OPTIONS</http-method>
<http-method>TRACE</http-method>
</web-resource-collection>
<auth-constraint>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
4.已解密登录请求
配置SSL,具体见http://serisboy.iteye.com/admin/blogs/1320231
在web.xml加入如下配置。
- <security-constraint>
- <web-resource-collection >
- <web-resource-name >SSL</web-resource-name>
- <url-pattern>/*</url-pattern>
- </web-resource-collection>
- <user-data-constraint>
- <transport-guarantee>CONFIDENTIAL</transportguarantee>
- </user-data-constraint>
- </security-constraint>
<security-constraint>
<web-resource-collection >
<web-resource-name >SSL</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transportguarantee>
</user-data-constraint>
</security-constraint>
5.高速缓存的ssl页面
- 页面
- <meta http-equiv="Pragma" contect="no-cache">
页面
<meta http-equiv="Pragma" contect="no-cache">
- java代码
- response.setHeader("Pragma", "No-cache");
java代码
response.setHeader("Pragma", "No-cache");
6.目录列表
配置文件目标拒绝访问。
在conf/web.xml下:
- <servlet>
- <servlet-name> default </servlet-name>
- <servlet-class> org.apache.catalina.servlets.DefaultServlet </servlet-class>
- <init-param>
- <param-name> debug </param-name>
- <param-value> 0 </param-value>
- </init-param>
- <init-param>
- <param-name> listings </param-name>
- <param-value> false </param-value>
- </init-param>
- <load-on-startup> 1 </load-on-startup>
- </servlet>
<servlet>
<servlet-name> default </servlet-name>
<servlet-class> org.apache.catalina.servlets.DefaultServlet </servlet-class>
<init-param>
<param-name> debug </param-name>
<param-value> 0 </param-value>
</init-param>
<init-param>
<param-name> listings </param-name>
<param-value> false </param-value>
</init-param>
<load-on-startup> 1 </load-on-startup>
</servlet>
把listings对应的value设置为fasle.
或者把上面的这个servlet加到你的虚拟路径下的web-inf/web.xml 中,把
servlet-name改为其它的,再加一下servlet-mapping
- <servlet>
- <servlet-name> default1 </servlet-name>
- <servlet-class> org.apache.catalina.servlets.DefaultServlet </servlet-class>
- <init-param>
- <param-name> debug </param-name>
- <param-value> 0 </param-value>
- </init-param>
- <init-param>
- <param-name> listings </param-name>
- <param-value> false </param-value>
- </init-param>
- <load-on-startup> 1 </load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name> default1 </servlet-name>
- <url-pattern> / </url-pattern>
- <servlet-mapping>