Недействительный токен 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 вы используете? То же самое работает у меня (однако есть различия spring-security.xml) с Spring 4.0.0 RELEASE (GA), Spring Security 3.2.0 RELEASE (GA) (хотя он интегрирован со Struts 2.3.16. Я не давал ему попробуйте только Spring MVC). Однако это не удается, когда запрос является составным для загрузки файлов со статусом 403. Я изо всех сил пытаюсь найти решение для этого.
Tiny

Spring 3.2.6, Spring Security 3.2.0, CSRF, токен был добавлен к объекту http-запроса, объект сеанса такой же, как и поток запроса, но при выходе, пока он не отобразит jsp, удалите все атрибуты и только оставить атрибут ... filter_applied
Хьюго Робайо

@Tiny: Вы когда-нибудь находили решение многостраничной проблемы? У меня точно такая же проблема.
Роб Йохансен

1
@AlienBishop: Да, пожалуйста, ознакомьтесь с этим ответом (в нем используется комбинация Spring и Struts). Если у вас есть только Spring MVC, ознакомьтесь с этим ответом. Следует отметить, что порядок фильтров web.xmlимеет решающее значение. MultipartFilterдолжен быть объявлен раньше springSecurityFilterChain. Надеюсь, это поможет. Спасибо.
Tiny

Ответы:


113

Похоже, что в вашем приложении Spring включена защита CSRF (подделка межсайтовых запросов). Собственно по умолчанию он включен.

По данным 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

В приведенном выше ответе избегайте использования стиля параметра запроса. Если вы сделаете это, вы выставите токены публично.
Прамод С. Никам

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


7

К чабрецу вы можете добавить:

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

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 07

4

У меня была такая же проблема.

В вашей конфигурации используется security = "none", поэтому невозможно создать _csrf:

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

вы можете установить access = "IS_AUTHENTICATED_ANONYMOUSLY" для страницы /login.jsp, заменив вышеуказанную конфигурацию :

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


1

Пожалуйста, посмотрите мой рабочий образец приложения на Github и сравните его с вашей настройкой.


Перейду на весеннюю 3.2.6, надеюсь, что без Spring mvc работает.
Хьюго Робайо,

Да, он должен работать без проблем, поскольку я создал образец приложения из моего существующего приложения, которое было на Spring 3.1.4.
Manish

ха-ха-ха-ха, отлично, чтобы он работал, просто понижение версии не является решением bhaiya ji @manish
Kuldeep Singh

1

Ни одно из решений у меня не сработало. Единственное, что сработало для меня в форме Spring, это:

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

ЗАМЕНЕН НА:

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

(Spring 5 с включенным csrf в конфигурации java)


0

В вашем контроллере добавьте следующее:

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

И на странице jsp добавьте

<form:form modelAttribute="someName" action="someURI?${_csrf.parameterName}=${_csrf.token}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.