W parametrze żądania „_csrf” lub nagłówku „X-CSRF-TOKEN” znaleziono nieprawidłowy token CSRF „null”

91

Po skonfigurowaniu Spring Security 3.2 _csrf.tokennie jest powiązany z żądaniem ani obiektem sesji.

Oto konfiguracja zabezpieczeń wiosny:

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

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

I renderuje następny html:

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

Wynikiem jest stan HTTP 403:

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

UPDATE Po pewnym debugowaniu obiekt żądania wychodzi dobrze z DelegatingFilterProxy, ale w linii 469 CoyoteAdapter wykonuje request.recycle (); która usuwa wszystkie atrybuty ...

Testuję w Tomcat 6.0.36, 7.0.50 z JDK 1.7.

Nie zrozumiałem tego zachowania, a raczej byłoby to możliwe, gdyby ktoś wskazał mi kierunek wojny z próbkami aplikacji ze Spring Security 3.2, który działa z CSRF.

Hugo Robayo
źródło
1
Jakiej wersji Spring używasz? To samo działa dla mnie (są jednak różnice w spring-security.xml) z Spring 4.0.0 RELEASE (GA), Spring Security 3.2.0 RELEASE (GA) (chociaż jest zintegrowany z Struts 2.3.16. Nie dałem mu spróbuj z samym Spring MVC). Jednak kończy się to niepowodzeniem, gdy żądanie jest wieloczęściowe, aby przesłać pliki o stanie 403. Trudno mi znaleźć rozwiązanie tego problemu.
Mały
Spring 3.2.6, Spring Security 3.2.0, CSRF, token został dodany do obiektu http-request, obiekt sesji jest taki sam wraz z wątkiem żądania, ale gdy wyjdzie do momentu renderowania jsp usuwa wszystkie atrybuty i tylko zostaw atrybut ... filter_applied
Hugo Robayo
@Tiny: Czy kiedykolwiek znalazłeś rozwiązanie problemu wieloczęściowego? Mam dokładnie ten sam problem.
Rob Johansen,
1
@AlienBishop: Tak, sprawdź odpowiedź (używa kombinacji sprężyny i rozpórki). Jeśli masz sam Spring MVC, sprawdź odpowiedź. Należy zauważyć, że kolejność filtrów web.xmljest kluczowa. MultipartFilternależy zgłosić wcześniej springSecurityFilterChain. Mam nadzieję, że to pomoże. Dzięki.
Malutki

Odpowiedzi:

113

Wygląda na to, że ochrona CSRF (Cross Site Request Forgery) w Twojej aplikacji Spring jest włączona. W rzeczywistości jest domyślnie włączona.

Według spring.io :

Kiedy należy stosować ochronę CSRF? Naszym zaleceniem jest stosowanie ochrony CSRF w przypadku wszelkich żądań, które mogą być przetwarzane przez przeglądarkę przez zwykłych użytkowników. Jeśli tworzysz tylko usługę używaną przez klientów innych niż przeglądarki, prawdopodobnie będziesz chciał wyłączyć ochronę CSRF.

Aby to wyłączyć:

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

Jeśli jednak chcesz, aby ochrona CSRF była włączona, musisz dołączyć do swojego formularza rozszerzenie csrftoken. Możesz to zrobić w ten sposób:

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

Możesz nawet dołączyć token CSRF do akcji formularza:

<form action="./upload?${_csrf.parameterName}=${_csrf.token}" method="post" enctype="multipart/form-data">
MaVRoSCy
źródło
2
Należy to zaakceptować jako odpowiedź, ponieważ wyjaśnia nie tylko, co należy zrobić, ale także co należy wziąć pod uwagę, zanim zrobisz coś, aby powstrzymać te błędy.
Thomas Carlisle,
1
Możesz także to zrobić.csrf().ignoringAntMatchers("/h2-console/**")
insan-e
W powyższej odpowiedzi unikaj przechodzenia przez styl parametrów zapytania. Jeśli to zrobisz, ujawniasz tokeny publicznie.
Pramod S. Nikam
32

Nie powinieneś dodawać do formularza logowania ?;

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

Jak stwierdzono tutaj w dokumentacji bezpieczeństwa Spring

borjab
źródło
12

Jeśli złożysz wniosek, security="none"nie zostanie wygenerowany żaden token csrf. Strona nie przejdzie przez filtr bezpieczeństwa. Użyj roli ANONYMOUS.

Nie wchodziłem w szczegóły, ale to działa dla mnie.

 <http auto-config="true" use-expressions="true">
   <intercept-url pattern="/login.jsp" access="hasRole('ANONYMOUS')" />
   <!-- you configuration -->
   </http>
Awanish Kumar
źródło
Użyłem security = none i przejście do Twojej odpowiedzi rozwiązało ten problem. to jest niesamowite thymeleaf automatycznie dodaje token csrf. Dzięki !
rxx
7

Spróbuj to zmienić: <csrf /> to: <csrf disabled="true"/>. Powinien wyłączyć csfr.

Arkadiusz Gibes
źródło
7

Do grasicy można dodać:

<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
Lay Leangsros
źródło
4

Miałem kiedyś ten sam problem.

Twoja konfiguracja używa security = "none", więc nie można wygenerować _csrf:

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

możesz ustawić access = "IS_AUTHENTICATED_ANONYMOUSLY" dla strony /login.jsp zastąp powyższą konfigurację :

<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
źródło
2

myślę, że csrf działa tylko z formami sprężynowymi

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

zmień form:formtag i zobacz, jak działa.

Saurabh Kumar
źródło
Nie musisz używać formularzy wiosennych: docs.spring.io/spring-security/site/docs/3.2.7.RELEASE/…
Bart Swennenhuis Kwietnia
1

Zobacz moją działającą przykładową aplikację na Github i porównaj z konfiguracją.

manish
źródło
Zejdę na wiosnę 3.2.6, mam nadzieję, że będzie działać bez wiosennego mvc.
Hugo Robayo,
Tak, powinno działać bez problemów, ponieważ utworzyłem przykładową aplikację z mojej istniejącej aplikacji, która była na Spring 3.1.4.
manisz
ha ha ha ha ha, świetnie, żeby to działało, po prostu obniżenie oceny nie jest rozwiązaniem bhaiya ji @manish
Kuldeep Singh
1

Żadne z rozwiązań u mnie nie zadziałało. Jedyne, które zadziałało dla mnie w formie wiosennej to:

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

WYMIANA:

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

(Wiosna 5 z włączonym csrf w konfiguracji java)

vancho
źródło
0

W kontrolerze dodaj następujące informacje:

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

A na stronie jsp dodaj

<form:form modelAttribute="someName" action="someURI?${_csrf.parameterName}=${_csrf.token}
Taras Melnyk
źródło