我有一个安静的后端,React + Redux前端,我试图防止CSRF和XSS攻击。
前端从API请求CSRF令牌。 API响应在HttpOnly cookie和响应正文中设置CSRF令牌。 redux reducer将令牌(从响应主体)保存到redux存储。
如果我在主容器componentDidMount()
中请求令牌,一切正常,但关注的是这是一次性的。相反,当对API的请求通过自定义中间件时,如果它不在本地存在,我宁愿中间件请求CSRF令牌。
流程如下(在Chrome 50和Firefox 47上测试):
X-CSRF-Token
标头设置的原始API调用。 未发送Cookie 如果我在使用window.setTimeout
的第2步之前添加了延迟,则Cookie仍然不会被发送,因此我认为它与浏览器的竞争条件<\ n>没有足够的时间保存cookie?
行动创作者
const login = (credentials) => {
return {
type: AUTH_LOGIN,
payload: {
api: {
method: 'POST',
url: api.v1.auth.login,
data: credentials
}
}
};
};
中间件
/**
* Ensure the crumb and JWT authentication token are wrapped in all requests to the API.
*/
export default (store) => (next) => (action) => {
if (action.payload && action.payload.api) {
store.dispatch({ type: `${action.type}_${PENDING}` });
return ensureCrumb(store)
.then((crumb) => {
const state = store.getState();
const requestConfig = {
...action.payload.api,
withCredentials: true,
xsrfCookieName: 'crumb',
xsrfHeaderName: 'X-CSRF-Token',
headers: {
'X-CSRF-Token': crumb
}
};
if (state.auth.token) {
requestConfig.headers = { ...requestConfig.headers, Authorization: `Bearer ${state.auth.token}` };
}
return axios(requestConfig);
})
.then((response) => store.dispatch({ type:`${action.type}_${SUCCESS}`, payload: response.data }))
.catch((response) => store.dispatch({ type: `${action.type}_${FAILURE}`, payload: response.data }));
}
return next(action);
};
/**
* Return the crumb if it exists, otherwise requests a crumb
* @param store - The current redux store
* @returns Promise - crumb token
*/
const ensureCrumb = (store) => {
const state = store.getState();
return new Promise((resolve, reject) => {
if (state.crumb.token) {
return resolve(state.crumb.token);
}
store.dispatch({ type: CRUMB_PENDING });
axios.get(api.v1.crumb)
.then((response) => {
store.dispatch({ type: CRUMB_SUCCESS, payload: { token: response.data.crumb } });
window.setTimeout(() => resolve(response.data.crumb), 10000);
// return resolve(response.data.crumb);
})
.catch((error) => {
store.dispatch({ type: CRUMB_FAILURE });
return reject(error);
});
});
};
答案 0 :(得分:1)
这是因为我在每个请求上创建了一个新的axios客户端,如果我为所有API请求重复使用相同的axios客户端,则cookie会正确保存并在后续请求中使用。