พบโทเค็น CSRF 'null' ที่ไม่ถูกต้องในพารามิเตอร์คำขอ '_csrf' หรือส่วนหัว 'X-CSRF-TOKEN'


91

หลังจากกำหนดค่า Spring Security 3.2 แล้ว_csrf.tokenจะไม่ถูกผูกไว้กับคำขอหรือวัตถุเซสชัน

นี่คือการกำหนดค่าความปลอดภัยสปริง:

<http pattern="/login.jsp" security="none"/>

<http>
    <intercept-url pattern="/**" access="ROLE_USER"/>
    <form-login login-page="/login.jsp"
                authentication-failure-url="/login.jsp?error=1"
                default-target-url="/index.jsp"/>
    <logout/>
    <csrf />
</http>

<authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="test" password="test" authorities="ROLE_USER/>
        </user-service>
    </authentication-provider>
</authentication-manager>

ไฟล์ login.jsp

<form name="f" action="${contextPath}/j_spring_security_check" method="post" >
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
    <button id="ingresarButton"
            name="submit"
            type="submit"
            class="right"
            style="margin-right: 10px;">Ingresar</button>
    <span>
        <label for="usuario">Usuario :</label>
        <input type="text" name="j_username" id="u" class="" value=''/>
    </span>
    <span>
        <label for="clave">Contrase&ntilde;a :</label>

        <input type="password"
               name="j_password"
               id="p"
               class=""
               onfocus="vc_psfocus = 1;"
               value="">
    </span>
</form>

และแสดงผล html ถัดไป:

<input type="hidden" name="" value="" />

ผลลัพธ์คือสถานะ HTTP 403:

Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.

อัปเดต หลังจากดีบักบางอย่างอ็อบเจ็กต์ที่ร้องขอจะออกมาในรูปแบบ DelegatingFilterProxy ที่ดี แต่ในบรรทัด 469 ของ CoyoteAdapter จะดำเนินการ request.recycle (); ที่ลบคุณลักษณะทั้งหมด ...

ฉันทดสอบใน Tomcat 6.0.36, 7.0.50 กับ JDK 1.7

ฉันไม่เข้าใจพฤติกรรมนี้แทนที่จะเป็นไปได้ถ้ามีคนชี้ฉันไปในทิศทางของสงครามตัวอย่างแอปพลิเคชันกับ Spring Security 3.2 ที่ทำงานร่วมกับ CSRF


1
คุณใช้ Spring version อะไร? สิ่งเดียวกันนี้ใช้ได้กับฉัน (มีความแตกต่างอย่างไรก็ตามในspring-security.xml) กับ Spring 4.0.0 RELEASE (GA), Spring Security 3.2.0 RELEASE (GA) (แม้ว่าจะรวมเข้ากับ Struts 2.3.16 ฉันไม่ได้ให้ ลองใช้ Spring MVC เพียงอย่างเดียว) อย่างไรก็ตามมันล้มเหลวเมื่อคำขอเป็นหลายส่วนสำหรับการอัปโหลดไฟล์ที่มีสถานะ 403 ฉันกำลังดิ้นรนเพื่อหาวิธีแก้ไข
จิ๋ว

Spring 3.2.6, Spring Security 3.2.0, CSRF, โทเค็นถูกเพิ่มเข้าไปในอ็อบเจ็กต์ http-request อ็อบเจ็กต์เซสชันจะเหมือนกันพร้อมกับเธรดคำขอ แต่เมื่อออกไปจนกว่าจะแสดงผล jsp จะลบแอ็ตทริบิวต์ทั้งหมดออกและเท่านั้น ทิ้งแอตทริบิวต์ ... filter_applied
Hugo Robayo

@Tiny: คุณเคยหาวิธีแก้ปัญหาหลายส่วนหรือไม่? ฉันมีแน่นอนปัญหาเดียวกัน
Rob Johansen

1
@AlienBishop: ใช่โปรดตรวจสอบคำตอบนี้ (ใช้การผสมผสานระหว่าง Spring และ Struts) หากคุณมีฤดูใบไม้ผลิ MVC คนเดียวแล้วโปรดตรวจสอบนี้คำตอบ ควรสังเกตว่าลำดับของตัวกรองweb.xmlเป็นสิ่งสำคัญ จะต้องประกาศก่อนMultipartFilter springSecurityFilterChainหวังว่าจะช่วยได้ ขอบคุณ.
จิ๋ว

คำตอบ:


113

ดูเหมือนว่าการป้องกัน CSRF (การปลอมแปลงคำขอข้ามไซต์) ในแอปพลิเคชัน Spring ของคุณถูกเปิดใช้งาน จริงๆแล้วมันถูกเปิดใช้งานโดยค่าเริ่มต้น

อ้างอิงจากspring.io :

คุณควรใช้การป้องกัน CSRF เมื่อใด คำแนะนำของเราคือใช้การป้องกัน CSRF สำหรับคำขอใด ๆ ที่เบราว์เซอร์สามารถดำเนินการได้โดยผู้ใช้ทั่วไป หากคุณกำลังสร้างบริการที่ใช้โดยไคลเอนต์ที่ไม่ใช่เบราว์เซอร์เท่านั้นคุณอาจต้องการปิดใช้งานการป้องกัน CSRF

ดังนั้นเพื่อปิดการใช้งาน:

@Configuration
public class RestSecurityConfig extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable();
  }
}

หากคุณต้องการเปิดใช้งานการป้องกัน CSRF ไว้คุณต้องรวมไว้ในรูปแบบของไฟล์csrftoken. คุณสามารถทำได้ดังนี้:

<form .... >
  ....other fields here....
  <input type="hidden"  name="${_csrf.parameterName}"   value="${_csrf.token}"/>
</form>

คุณยังสามารถรวมโทเค็น CSRF ในการดำเนินการของแบบฟอร์ม:

<form action="./upload?${_csrf.parameterName}=${_csrf.token}" method="post" enctype="multipart/form-data">

2
สิ่งนี้ควรได้รับการยอมรับว่าเป็นคำตอบเพราะไม่เพียง แต่อธิบายสิ่งที่ต้องทำเท่านั้น แต่ยังรวมถึงสิ่งที่คุณควรพิจารณาก่อนทำบางสิ่งเพื่อหยุดข้อผิดพลาดเหล่านี้ด้วย
Thomas Carlisle

1
คุณสามารถทำได้เช่นกัน.csrf().ignoringAntMatchers("/h2-console/**")
insan-e

ในคำตอบข้างต้นหลีกเลี่ยงการใช้สไตล์พารามิเตอร์การค้นหา หากคุณทำเช่นนี้คุณกำลังเปิดเผยโทเค็นในที่สาธารณะ
Pramod S. Nikam

32

คุณไม่ควรเพิ่มแบบฟอร์มเข้าสู่ระบบหรือไม่;

<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/> 

ตามที่ระบุไว้ที่นี่ในเอกสารความปลอดภัยของ Spring


12

หากคุณจะสมัครจะsecurity="none"ไม่มีการสร้างโทเค็น csrf หน้าจะไม่ผ่านตัวกรองความปลอดภัย ใช้บทบาทไม่ระบุชื่อ

ฉันไม่ได้ลงรายละเอียด แต่มันใช้ได้ผลสำหรับฉัน

 <http auto-config="true" use-expressions="true">
   <intercept-url pattern="/login.jsp" access="hasRole('ANONYMOUS')" />
   <!-- you configuration -->
   </http>

ฉันใช้ security = none และย้ายไปที่คำตอบของคุณเพื่อแก้ไขปัญหานี้ มันยอดเยี่ยมมากใบโหระพาเพิ่มโทเค็น csrf โดยอัตโนมัติ ขอบคุณ!
rxx



6

เอกสาร Spring เพื่อปิดการใช้งาน csrf: https://docs.spring.io/spring-security/site/docs/current/reference/html/csrf.html#csrf-configure

@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {

   @Override
   protected void configure(HttpSecurity http) throws Exception {
      http.csrf().disable();
   }
}

โปรดอย่าคัดลอกคำตอบที่มีอยู่
james.garriss

4

ผมเคยมีปัญหาเดียวกัน

การกำหนดค่าของคุณใช้ความปลอดภัย = "ไม่มี" จึงไม่สามารถสร้าง _csrf:

<http pattern="/login.jsp" security="none"/>

คุณสามารถตั้งค่าการเข้าถึง = "IS_AUTHENTICATED_ANONYMOUSLY" สำหรับเพจ /login.jsp แทนที่ config ด้านบน:

<http>
    <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <intercept-url pattern="/**" access="ROLE_USER"/>
    <form-login login-page="/login.jsp"
            authentication-failure-url="/login.jsp?error=1"
            default-target-url="/index.jsp"/>
    <logout/>
    <csrf />
</http>

2

ฉันคิดว่า csrf ใช้ได้กับสปริงฟอร์มเท่านั้น

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

เปลี่ยนเป็นform:formแท็กและดูว่าได้ผล


คุณไม่จำเป็นต้องใช้สปริงฟอร์ม: docs.spring.io/spring-security/site/docs/3.2.7.RELEASE/…
Bart Swennenhuis

1

โปรดดูแอปพลิเคชันตัวอย่างการทำงานของฉันบน Githubและเปรียบเทียบกับการตั้งค่าของคุณ


ฉันจะปรับลดรุ่นเป็นสปริง 3.2.6 ฉันหวังว่ามันจะใช้งานได้โดยไม่ต้องสปริง mvc
Hugo Robayo

ใช่มันควรจะใช้งานได้โดยไม่มีปัญหาเมื่อฉันสร้างแอปพลิเคชันตัวอย่างจากแอปพลิเคชันที่มีอยู่ของฉันซึ่งอยู่ใน Spring 3.1.4
manish

ฮ่าฮ่าฮ่าฮ่าดีมากที่ทำให้มันใช้งานได้เพียงแค่การปรับลดรุ่นไม่ใช่วิธีแก้ bhaiya ji @manish
Kuldeep Singh

1

ไม่มีวิธีแก้ปัญหาใดวิธีหนึ่งที่ใช้ได้ผลกับฉัน สิ่งเดียวที่เหมาะกับฉันในรูปแบบฤดูใบไม้ผลิคือ:

action = "./ upload? $ {_ csrf.parameterName} = $ {_ csrf.token}"

แทนที่ด้วย:

action = "./ อัปโหลด? _csrf = $ {_ csrf.token}"

(สปริง 5 พร้อมเปิดใช้งาน csrf ในการกำหนดค่า java)


0

ในคอนโทรลเลอร์ของคุณให้เพิ่มสิ่งต่อไปนี้:

@RequestParam(value = "_csrf", required = false) String csrf

และในหน้า jsp เพิ่ม

<form:form modelAttribute="someName" action="someURI?${_csrf.parameterName}=${_csrf.token}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.