Token CSRF 'null' tidak valid ditemukan di parameter permintaan '_csrf' atau header 'X-CSRF-TOKEN'

91

Setelah mengkonfigurasi Spring Security 3.2, _csrf.tokentidak terikat pada permintaan atau objek sesi.

Ini adalah konfigurasi keamanan pegas:

<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>

File 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>

Dan itu membuat html berikutnya:

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

Hasilnya adalah status HTTP 403:

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

UPDATE Setelah beberapa debug, objek permintaan keluar dari DelegatingFilterProxy, tetapi dalam baris 469 CoyoteAdapter itu mengeksekusi request.recycle (); yang menghapus semua atribut ...

Saya menguji di Tomcat 6.0.36, 7.0.50 dengan JDK 1.7.

Saya belum memahami perilaku ini, alih-alih, ini akan menjadi mungkin jika seseorang mengarahkan saya ke beberapa contoh aplikasi perang dengan Spring Security 3.2 yang bekerja dengan CSRF.

Hugo Robayo
sumber
1
Versi Spring apa yang Anda gunakan? Hal yang sama ini berfungsi untuk saya (namun ada perbedaan spring-security.xml) dengan Spring 4.0.0 RELEASE (GA), Spring Security 3.2.0 RELEASE (GA) (meskipun terintegrasi dengan Struts 2.3.16. Saya tidak memberikannya coba dengan Spring MVC saja). Namun gagal, ketika permintaan multipart untuk mengupload file dengan status 403. Saya berjuang untuk menemukan solusi untuk itu.
Tiny
Spring 3.2.6, Spring Security 3.2.0, CSRF, token telah ditambahkan ke objek http-request, objek sesi sama dengan utas permintaan, tetapi ketika keluar hingga membuat jsp menghapus semua atribut dan hanya tinggalkan atribut ... filter_applied
Hugo Robayo
@Tiny: Apakah Anda pernah menemukan solusi untuk masalah multi bagian? Saya mengalami masalah yang sama persis .
Rob Johansen
1
@AlienBishop: Ya, silakan periksa jawaban ini (menggunakan kombinasi Spring dan Struts). Jika Anda memiliki Spring MVC saja, silakan lihat jawaban ini . Perlu dicatat bahwa urutan filter web.xmlsangat penting. MultipartFilterharus diumumkan sebelumnya springSecurityFilterChain. Semoga membantu. Terima kasih.
Tiny

Jawaban:

113

Sepertinya perlindungan CSRF (Cross Site Request Forgery) di aplikasi Spring Anda diaktifkan. Sebenarnya itu diaktifkan secara default.

Menurut spring.io :

Kapan Anda harus menggunakan perlindungan CSRF? Rekomendasi kami adalah menggunakan perlindungan CSRF untuk permintaan apa pun yang dapat diproses oleh browser oleh pengguna biasa. Jika Anda hanya membuat layanan yang digunakan oleh klien non-browser, Anda mungkin ingin menonaktifkan perlindungan CSRF.

Jadi untuk menonaktifkannya:

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

Jika Anda ingin tetap mengaktifkan perlindungan CSRF, Anda harus menyertakan file csrftoken. Anda bisa melakukannya seperti ini:

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

Anda bahkan dapat menyertakan token CSRF dalam tindakan formulir:

<form action="./upload?${_csrf.parameterName}=${_csrf.token}" method="post" enctype="multipart/form-data">
MaVRoSCy
sumber
2
Ini harus diterima sebagai jawaban karena menjelaskan tidak hanya apa yang harus dilakukan, tetapi juga apa yang harus Anda pertimbangkan sebelum melakukan sesuatu untuk menghentikan kesalahan ini.
Thomas Carlisle
1
Anda juga dapat melakukannya.csrf().ignoringAntMatchers("/h2-console/**")
insan-e
Dalam jawaban di atas, hindari melalui gaya parameter kueri. Jika Anda melakukan ini, Anda mengekspos token di depan umum.
Pramod S. Nikam
32

Bukankah sebaiknya Anda menambahkan ke formulir login ?;

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

Seperti yang dinyatakan di sini di dokumentasi keamanan Spring

borjab.dll
sumber
12

Jika Anda akan mendaftar security="none"maka tidak ada token csrf yang akan dibuat. Halaman tidak akan melewati filter keamanan. Gunakan peran ANONIM.

Saya belum menjelaskan secara detail, tetapi ini berfungsi untuk saya.

 <http auto-config="true" use-expressions="true">
   <intercept-url pattern="/login.jsp" access="hasRole('ANONYMOUS')" />
   <!-- you configuration -->
   </http>
Awanish Kumar
sumber
Saya menggunakan security = none dan pindah ke jawaban Anda memecahkan masalah ini. itu mengagumkan thymeleaf secara otomatis menambahkan token csrf. Terima kasih!
rxx
7

Cobalah untuk mengubah ini: <csrf /> untuk ini: <csrf disabled="true"/>. Ini harus menonaktifkan csfr.

Arkadiusz Gibes
sumber
7

Dengan daun timel Anda dapat menambahkan:

<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
Lay Leangsros
sumber
4

Saya dulu punya masalah yang sama.

Konfigurasi Anda menggunakan security = "none" jadi tidak dapat menghasilkan _csrf:

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

Anda dapat mengatur access = "IS_AUTHENTICATED_ANONYMOUSLY" untuk halaman /login.jsp menggantikan konfigurasi di atas :

<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>
xxg
sumber
2

Saya pikir csrf hanya bekerja dengan bentuk pegas

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

ubah ke form:formtag dan lihat apakah berfungsi.

Saurabh Kumar
sumber
Anda tidak perlu menggunakan formulir pegas: docs.spring.io/spring-security/site/docs/3.2.7.RELEASE/…
Bart Swennenhuis
1

Silakan lihat aplikasi sampel kerja saya di Github dan bandingkan dengan pengaturan Anda.

manish
sumber
Saya akan menurunkan versi ke pegas 3.2.6, saya harap ini berfungsi tanpa pegas mvc.
Hugo Robayo
Ya, ini akan bekerja tanpa masalah karena saya membuat aplikasi sampel dari aplikasi saya yang ada pada Spring 3.1.4.
manish
ha ha ha ha ha, bagus, untuk membuatnya bekerja hanya menurunkan bukanlah solusi bhaiya ji @manish
Kuldeep Singh
1

Tidak ada satu pun solusi yang berhasil dari saya. Satu-satunya yang berhasil untuk saya dalam bentuk Spring adalah:

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

DIGANTIKAN DENGAN:

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

(Spring 5 dengan csrf yang diaktifkan dalam konfigurasi java)

vancho.dll
sumber
0

Di pengontrol Anda, tambahkan yang berikut ini:

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

Dan di halaman jsp tambahkan

<form:form modelAttribute="someName" action="someURI?${_csrf.parameterName}=${_csrf.token}
Taras Melnyk
sumber