• 超详细的cookie属性HttpOnly和SameSite引起的漏洞解决方案


            我们项目上线前都经过漏洞扫描,并针对漏扫报告修改存在的漏洞,每次扫描都有2个关于cookie方面的漏扫(漏洞级别属于低),漏洞名字分别是:Cookie No HttpOnly Flag 和 Cookie Without SameSite Attribute。每次上线前漏扫,测试同事都催着让改(由于属于低级别漏洞,都一直拖着),我看以前同事改过几次,但是都没起作用,漏洞还存在。所以就研究一下,自己做下总结。

    关于这2个漏洞简单介绍

            Cookie No HttpOnly Flag:没有安全标签的cookie,需要把httponly属性设置为true;这样就可以防止跨站脚本攻击XSS(Cross Site script)。

            Cookie Without SameSite Attribute: 意思cookie的samesite属性设置了none,当samesite=none时,有可能存在跨站请求伪造CSRF(cross site request forgery)攻击的风险。samesite属性有三个值:Strict/Lax/None。具体意思大家自行百度吧。我们这里把samesite设置成Lax就可以了。

    错误的解决方案

            我也在网上查了很多资料,都是写个过滤器filter,然后在response里设置下,大概代码如下:

    response.setHeader("SameSite","Lax");
    response.setHeader("Set-Cookie","HttpOnly");

    其实我们就是这么改的,但是不生效,这2个漏洞还存在。在浏览器F12下看相关信息截图如下:

            在响应头里确实有了这个2个属性,由于前期对cookie的这2个属性不了解,以为这样就可以了,但是这是无法解决这2个漏洞的。

    错误解决方案的代码如下

    1. package com.lsl.mylsl.filter;
    2. import org.springframework.stereotype.Component;
    3. import javax.servlet.*;
    4. import javax.servlet.http.Cookie;
    5. import javax.servlet.http.HttpServletRequest;
    6. import javax.servlet.http.HttpServletResponse;
    7. import java.io.IOException;
    8. @Component
    9. public class CookieFilter implements Filter {
    10. @Override
    11. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    12. HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
    13. HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
    14. //这里模拟下浏览器发送请求中包含三个cookie,
    15. // 因为后端在request中无法添加cookie,咱们就先添加到response中,
    16. //第一次请求把三个cookie带到客户端,再请求时浏览器就把这三个cookie带过来了
    17. Cookie cookie1 = new Cookie("name","lsl");
    18. httpResponse.addCookie(cookie1);
    19. Cookie cookie2 = new Cookie("age","18");
    20. httpResponse.addCookie(cookie2);
    21. Cookie cookie3 = new Cookie("addr","beijing");
    22. httpResponse.addCookie(cookie3);
    23. httpResponse.setHeader("SameSite","Lax");
    24. httpResponse.setHeader("Set-Cookie","HttpOnly");
    25. filterChain.doFilter(httpRequest,httpResponse);
    26. }
    27. }

    如果解决了这2个漏洞,正确的截图如下

    图1:

    图2:下图红色框上面的也有三个set-cookie属性,分别有三个cookie,但是后面没有httponly和samesite属性。原因我在代码里模拟了客户端发送请求里放了三个cookie。这是第一次请求时添加的heeader属性,红色框里是第二次请求request才把三个cookie带过来,所以才有这2个属性。大家可以看后面附的正确解决方案的代码

    图3:

    正确方案的代码如下:

    1. package com.lsl.mylsl.filter;
    2. import org.springframework.http.HttpHeaders;
    3. import org.springframework.http.ResponseCookie;
    4. import org.springframework.stereotype.Component;
    5. import javax.servlet.*;
    6. import javax.servlet.http.Cookie;
    7. import javax.servlet.http.HttpServletRequest;
    8. import javax.servlet.http.HttpServletResponse;
    9. import java.io.IOException;
    10. @Component
    11. public class CookieFilter implements Filter {
    12. @Override
    13. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    14. HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
    15. HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
    16. //这里模拟下浏览器发送请求中包含三个cookie,
    17. // 因为后端在request中无法添加cookie,咱们就先添加到response中,
    18. //第一次请求把三个cookie带到客户端,再请求时浏览器就把这三个cookie带过来了
    19. Cookie cookie1 = new Cookie("name","lsl");
    20. httpResponse.addCookie(cookie1);
    21. Cookie cookie2 = new Cookie("age","18");
    22. httpResponse.addCookie(cookie2);
    23. Cookie cookie3 = new Cookie("addr","beijing");
    24. httpResponse.addCookie(cookie3);
    25. String url = httpRequest.getRequestURL().toString();
    26. Cookie[] cookies = httpRequest.getCookies();
    27. if (cookies != null){
    28. StringBuilder sb = new StringBuilder();
    29. for (Cookie cookie : cookies){
    30. String cookieName = cookie.getName();
    31. String cookieValue = cookie.getValue();
    32. System.out.println("url = " + url + ", cookieName = " + cookieName + ", cookieValue = " + cookieValue);
    33. ResponseCookie lastCookie = ResponseCookie.from(cookieName, cookieValue).httpOnly(true).sameSite("Lax").build();
    34. httpResponse.addHeader(HttpHeaders.SET_COOKIE,lastCookie.toString());
    35. }
    36. }
    37. filterChain.doFilter(httpRequest,httpResponse);
    38. }
    39. }

            发现没有,我正确的解决方案里除了遍历了cookie,添加属性时用的是response.addHeader("Set-cookie",String)方法,而错误的解决方案中用的是response.setHeader("Set-Cookie",String)方法。

            httponly和samesite属性是属于cookie的,所以必须遍历所有cookie,并设置这些相关属性,当然cookie还有其他好多属性(domain,path,maxAge等)。错误方案里只是给响应头添加了属性,所以没法解决这2个漏洞问题。对应请求中有多个cookie,必须用addHeader方法,如果只有一个cookie可以使用setHeader方法。

    response.addHeader()和response.setHeader的区别

    这2个方法都是给response的header添加属性,但是略有区别,

    response.setHeader():如果存在key就替换value

    response.addHeader(): 如果key存在也不替换value,而是增加

            这里我先说下Set-Cookie属性,其实是一个cookie对应一个Set-Cookie属性,我开始以为是Set-Cookie里放所有cookie,然后后面的httponly等属性一起修饰前面的cookie。其实不是的,当然如果你一个Set-Cookie属性了前面放了多个cookie,后面的httponly; SameSite=Lax 属性只对第一个cookie生效,这个我测试过了。代码和截图如下:

            

    1. package com.lsl.mylsl.filter;
    2. import org.springframework.http.HttpHeaders;
    3. import org.springframework.stereotype.Component;
    4. import javax.servlet.*;
    5. import javax.servlet.http.Cookie;
    6. import javax.servlet.http.HttpServletRequest;
    7. import javax.servlet.http.HttpServletResponse;
    8. import java.io.IOException;
    9. @Component
    10. public class CookieFilter implements Filter {
    11. @Override
    12. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    13. HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
    14. HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
    15. //这里模拟下浏览器发送请求中包含三个cookie,
    16. // 因为后端在request中无法添加cookie,咱们就先添加到response中,
    17. //第一次请求把三个cookie带到客户端,再请求时浏览器就把这三个cookie带过来了
    18. Cookie cookie1 = new Cookie("name","lsl");
    19. httpResponse.addCookie(cookie1);
    20. Cookie cookie2 = new Cookie("age","18");
    21. httpResponse.addCookie(cookie2);
    22. Cookie cookie3 = new Cookie("addr","beijing");
    23. httpResponse.addCookie(cookie3);
    24. String url = httpRequest.getRequestURL().toString();
    25. Cookie[] cookies = httpRequest.getCookies();
    26. if (cookies != null){
    27. StringBuilder sb = new StringBuilder();
    28. for (Cookie cookie : cookies){
    29. String cookieName = cookie.getName();
    30. String cookieValue = cookie.getValue();
    31. System.out.println("url = " + url + ", cookieName = " + cookieName + ", cookieValue = " + cookieValue);
    32. // ResponseCookie lastCookie = ResponseCookie.from(cookieName, cookieValue).httpOnly(true).sameSite("Lax").build();
    33. sb.append(cookieName).append("=").append(cookieValue).append(";");
    34. }
    35. sb.append("HttpOnly; SameSite=Lax");
    36. httpResponse.addHeader(HttpHeaders.SET_COOKIE,sb.toString());
    37. }
    38. filterChain.doFilter(httpRequest,httpResponse);
    39. }
    40. }

            

    发现只有第一个cookie的httponly和samesite生效了

            我们再说下,response.addHeader("Set-cookie",String)和response.setHeader("Set-Cookie",String)的区别。根据上面的正确代码可以看出,如果采用response.setHeader("Set-Cookie",String),只是把最后一个cookie设置的httponly和sameSite属性生效了。这个2个方法我也都测试过了。

    用setHeader方法,只有最后一个cookie生效了,相关的代码和截图如下

    1. package com.lsl.mylsl.filter;
    2. import org.springframework.http.HttpHeaders;
    3. import org.springframework.http.ResponseCookie;
    4. import org.springframework.stereotype.Component;
    5. import javax.servlet.*;
    6. import javax.servlet.http.Cookie;
    7. import javax.servlet.http.HttpServletRequest;
    8. import javax.servlet.http.HttpServletResponse;
    9. import java.io.IOException;
    10. @Component
    11. public class CookieFilter implements Filter {
    12. @Override
    13. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    14. HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
    15. HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
    16. //这里模拟下浏览器发送请求中包含三个cookie,
    17. // 因为后端在request中无法添加cookie,咱们就先添加到response中,
    18. //第一次请求把三个cookie带到客户端,再请求时浏览器就把这三个cookie带过来了
    19. Cookie cookie1 = new Cookie("name","lsl");
    20. httpResponse.addCookie(cookie1);
    21. Cookie cookie2 = new Cookie("age","18");
    22. httpResponse.addCookie(cookie2);
    23. Cookie cookie3 = new Cookie("addr","beijing");
    24. httpResponse.addCookie(cookie3);
    25. String url = httpRequest.getRequestURL().toString();
    26. Cookie[] cookies = httpRequest.getCookies();
    27. if (cookies != null){
    28. StringBuilder sb = new StringBuilder();
    29. for (Cookie cookie : cookies){
    30. String cookieName = cookie.getName();
    31. String cookieValue = cookie.getValue();
    32. System.out.println("url = " + url + ", cookieName = " + cookieName + ", cookieValue = " + cookieValue);
    33. ResponseCookie lastCookie = ResponseCookie.from(cookieName, cookieValue).httpOnly(true).sameSite("Lax").build();
    34. httpResponse.setHeader(HttpHeaders.SET_COOKIE,lastCookie.toString());
    35. }
    36. }
    37. filterChain.doFilter(httpRequest,httpResponse);
    38. }
    39. }

  • 相关阅读:
    叉树的逆向有序遍历(C/C++实现)
    8、IOC 之容器扩展点
    迁移学习:互信息的变分上下界
    在代码空间中使用源控制
    【学习】如何高效地进行集成测试
    微信小程序 官方文档使用指南
    易基因|疾病研究:DNA甲基化与转录组分析联合揭示吸烟免疫相关疾病的表观遗传机制
    设计模式的七大原则(建议收藏)
    智能服务机器人产品及解决方案
    Spring 事务原理总结五
  • 原文地址:https://blog.csdn.net/dhklsl/article/details/126425087