超詳細な Cookie 属性 HttpOnly および SameSite による脆弱性ソリューション

        私たちのプロジェクトは、オンラインになる前に脆弱性をスキャンされました, 既存の脆弱性は、失敗したスキャンレポートに従って修正されました. 各スキャンには、Cookie に関する 2 つの失敗したスキャンがあります (脆弱性レベルは低いです). 脆弱性の名前は次のとおりです: Cookie No SameSite 属性のない HttpOnly フラグと Cookie。オンラインになる前にスキャンし忘れるたびに、テストの同僚から変更するように促されました (低レベルの脆弱性だったので、私は先延ばしにしました)。であり、脆弱性は依然として存在します。したがって、調査を行い、独自の結論を出すだけです。

これら 2 つの脆弱性の簡単な紹介

        Cookie No HttpOnly フラグ: セキュリティ タグのない Cookie の場合、httponly 属性を true に設定する必要があります。これにより、XSS (クロス サイト スクリプト) からのクロスサイト スクリプティング攻撃を防ぐことができます。

        SameSite 属性のない Cookie: Cookie の samesite 属性が none に設定されていることを意味します. samesite=none の場合、CSRF (クロス サイト リクエスト フォージェリ) 攻撃のリスクがある可能性があります. samesite 属性には、Strict/Lax/None の 3 つの値があります。具体的な意味は自分でバイドゥにすることができます。ここで、samesite を Lax に設定できます。

間違った解決策

        私もネットでいろいろ情報を調べて、フィルタフィルタを書いてレスポンスに設定したところ、おおよそのコードは以下のようになりました。

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

実際、このように変更したのですが、有効にはならず、この 2 つの抜け穴がまだ残っています。ブラウザ F12 の関連情報のスクリーンショットは次のとおりです。

        確かにレスポンスヘッダーにはこの2つの属性があり、初期の段階ではCookieのこの2つの属性を理解していなかったので、これで十分だと思っていましたが、この2つの脆弱性を解決することはできません。

エラー解決のコードは次のとおりです

package com.lsl.mylsl.filter;

import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class CookieFilter implements Filter {


    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;

        //这里模拟下浏览器发送请求中包含三个cookie,
        // 因为后端在request中无法添加cookie,咱们就先添加到response中,
        //第一次请求把三个cookie带到客户端,再请求时浏览器就把这三个cookie带过来了
        Cookie cookie1 = new Cookie("name","lsl");
        httpResponse.addCookie(cookie1);
        Cookie cookie2 = new Cookie("age","18");
        httpResponse.addCookie(cookie2);
        Cookie cookie3 = new Cookie("addr","beijing");
        httpResponse.addCookie(cookie3);


        httpResponse.setHeader("SameSite","Lax");
        httpResponse.setHeader("Set-Cookie","HttpOnly");
        filterChain.doFilter(httpRequest,httpResponse);
    }
}

これら 2 つの脆弱性が解決された場合、正しいスクリーンショットは次のようになります

図1:

図 2: 下図の赤いボックスの上にも 3 つの set-cookie 属性があり、それぞれ 3 つの Cookie がありますが、後ろに httponly 属性と samesite 属性はありません。その理由は、クライアントがリクエストで 3 つの Cookie を送信したことをコードでシミュレートしたためです。これは、最初のリクエストで追加されたヘッダー属性です。赤いボックス内は、3 つの Cookie を送信した 2 番目のリクエストであるため、これら 2 つの属性があります。後で添付された正しいソリューションのコードを見ることができます

画像 3:

正しいシナリオのコードは次のとおりです。

package com.lsl.mylsl.filter;

import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class CookieFilter implements Filter {


    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;

        //这里模拟下浏览器发送请求中包含三个cookie,
        // 因为后端在request中无法添加cookie,咱们就先添加到response中,
        //第一次请求把三个cookie带到客户端,再请求时浏览器就把这三个cookie带过来了
        Cookie cookie1 = new Cookie("name","lsl");
        httpResponse.addCookie(cookie1);
        Cookie cookie2 = new Cookie("age","18");
        httpResponse.addCookie(cookie2);
        Cookie cookie3 = new Cookie("addr","beijing");
        httpResponse.addCookie(cookie3);

        String url = httpRequest.getRequestURL().toString();

        Cookie[] cookies = httpRequest.getCookies();
        if (cookies != null){
            StringBuilder sb = new StringBuilder();
            for (Cookie cookie : cookies){
                String cookieName = cookie.getName();
                String cookieValue = cookie.getValue();
                System.out.println("url = " + url + ", cookieName = " + cookieName + ", cookieValue = " + cookieValue);
                ResponseCookie lastCookie = ResponseCookie.from(cookieName, cookieValue).httpOnly(true).sameSite("Lax").build();
                httpResponse.addHeader(HttpHeaders.SET_COOKIE,lastCookie.toString());

            }
        }

        filterChain.doFilter(httpRequest,httpResponse);
    }
}

        私の正しい解決策では、Cookie のトラバースに加えて、属性を追加するときに response.addHeader("Set-cookie", String) メソッドを使用しましたが、間違った解決策では response.setHeader("Set-Cookie",文字列) メソッド。

        httponly および samesite 属性は Cookie に属しているため、すべての Cookie をトラバースし、これらの関連する属性を設定する必要があります. もちろん、Cookie には他の多くの属性 (ドメイン、パス、maxAge など) もあります. 誤った解決策では、応答ヘッダーに属性のみが追加されるため、これら 2 つの脆弱性は解決できません。対応するリクエストに複数の Cookie がある場合は addHeader メソッドを使用する必要があり、Cookie が 1 つのみの場合は setHeader メソッドを使用できます。

response.addHeader() と response.setHeader の違い

この 2 つの方法は、応答のヘッダーに属性を追加する方法ですが、若干の違いがあります。

response.setHeader(): キーが存在する場合は値を置き換えます

response.addHeader(): キーが存在する場合、値を置き換えませんが、増加します

        ここでまず Set-Cookie 属性について説明します. 実は Cookie は Set-Cookie 属性に対応しています. 最初はすべての Cookie が Set-Cookie に置かれていると思っていました.一緒にクッキー。もちろん、Set-Cookie 属性の前に複数の Cookie を配置すると、その後ろにある httponly; SameSite=Lax 属性は最初の Cookie に対してのみ有効になりますコードとスクリーンショットは次のとおりです。

        

package com.lsl.mylsl.filter;

import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class CookieFilter implements Filter {


    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;

        //这里模拟下浏览器发送请求中包含三个cookie,
        // 因为后端在request中无法添加cookie,咱们就先添加到response中,
        //第一次请求把三个cookie带到客户端,再请求时浏览器就把这三个cookie带过来了
        Cookie cookie1 = new Cookie("name","lsl");
        httpResponse.addCookie(cookie1);
        Cookie cookie2 = new Cookie("age","18");
        httpResponse.addCookie(cookie2);
        Cookie cookie3 = new Cookie("addr","beijing");
        httpResponse.addCookie(cookie3);

        String url = httpRequest.getRequestURL().toString();

        Cookie[] cookies = httpRequest.getCookies();
        if (cookies != null){
            StringBuilder sb = new StringBuilder();
            for (Cookie cookie : cookies){
                String cookieName = cookie.getName();
                String cookieValue = cookie.getValue();
                System.out.println("url = " + url + ", cookieName = " + cookieName + ", cookieValue = " + cookieValue);
//                ResponseCookie lastCookie = ResponseCookie.from(cookieName, cookieValue).httpOnly(true).sameSite("Lax").build();
                
                sb.append(cookieName).append("=").append(cookieValue).append(";");
            }
            sb.append("HttpOnly; SameSite=Lax");
            httpResponse.addHeader(HttpHeaders.SET_COOKIE,sb.toString());
        }

        filterChain.doFilter(httpRequest,httpResponse);
    }
}

        

最初の Cookie の httponly と samesite のみが有効であることがわかりました

        response.addHeader("Set-cookie", String) と response.setHeader("Set-Cookie", String) の違いについて話しましょう上記の正しいコードによると、response.setHeader("Set-Cookie", String) を使用すると、最後の Cookie によって設定された httponly および sameSite 属性のみが有効になることがわかります。この 2 つの方法もテストしました。

setHeader メソッドを使用すると、最後の Cookie のみが有効になります。関連するコードとスクリーンショットは次のとおりです

package com.lsl.mylsl.filter;

import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class CookieFilter implements Filter {


    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;

        //这里模拟下浏览器发送请求中包含三个cookie,
        // 因为后端在request中无法添加cookie,咱们就先添加到response中,
        //第一次请求把三个cookie带到客户端,再请求时浏览器就把这三个cookie带过来了
        Cookie cookie1 = new Cookie("name","lsl");
        httpResponse.addCookie(cookie1);
        Cookie cookie2 = new Cookie("age","18");
        httpResponse.addCookie(cookie2);
        Cookie cookie3 = new Cookie("addr","beijing");
        httpResponse.addCookie(cookie3);

        String url = httpRequest.getRequestURL().toString();

        Cookie[] cookies = httpRequest.getCookies();
        if (cookies != null){
            StringBuilder sb = new StringBuilder();
            for (Cookie cookie : cookies){
                String cookieName = cookie.getName();
                String cookieValue = cookie.getValue();
                System.out.println("url = " + url + ", cookieName = " + cookieName + ", cookieValue = " + cookieValue);
                ResponseCookie lastCookie = ResponseCookie.from(cookieName, cookieValue).httpOnly(true).sameSite("Lax").build();
                httpResponse.setHeader(HttpHeaders.SET_COOKIE,lastCookie.toString());
            }
        }

        filterChain.doFilter(httpRequest,httpResponse);
    }
}

おすすめ

転載: blog.csdn.net/dhklsl/article/details/126425087