Недействительный токен 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

Borjab
источник
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

Попробуйте изменить: <csrf /> к этому: <csrf disabled="true"/>. Он должен отключить csfr.

Аркадиуш Гибес
источник
7

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

<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/>
Lay Leangsros
источник
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>
xxg
источник
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/…
Барт Свенненхейс
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)

Vancho
источник
0

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

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

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

<form:form modelAttribute="someName" action="someURI?${_csrf.parameterName}=${_csrf.token}
Тарас Мельник
источник