当我通过JWT时,使用XSRF-TOKEN防止XSRF攻击为Angular应用扔了一个cookie。这就是我的HttpInterceptor
的样子。
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const headerName = "XSRF-TOKEN";
const respHeaderName = "X-XSRF-TOKEN";
let token = this.tokenExtractor.getToken() as string;
if (token !== null && !req.headers.has(headerName)) {
req = req.clone({ headers: req.headers.set(respHeaderName, token) });
}
return next.handle(req);
}
这会在控制台中弹出400 Bad Request错误,并显示一条消息:预检响应没有HTTP正常状态。如果我注释掉请求所在的代码行克隆,错误消失,我的HTTP请求顺利通过。
我的.htaccess
中的标题看起来像这样。
Header set Access-Control-Allow-Origin "http://localhost:4200"
Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Allow-Headers "Content-Type"
Header set Access-Control-Allow-Headers "Authorization"
Header set Access-Control-Allow-Headers "X-XSRF-TOKEN"
Header set Access-Control-Expose-Headers: "Authorization"
非常感谢您的帮助。
编辑1:我的MCVE PHP代码
$return = array();
if (isset($_POST["email"]) && isset($_POST["password"])) {
header("HTTP/1.0 200");
$return["msg"] = "random";
echo json_encode($return);
} else {
header("HTTP/1.0 400");
$return["error_message"] = "HTTP Post variables are not set!";
$return["friendly_error_message"] = "Client error!";
echo json_encode($return);
}
exit();
还有我的Angular服务中的verify()
函数。
verify(email: string, password: string): Observable<JSON> {
let headers = new HttpHeaders()
headers = headers.set("Content-Type", "application/x-www-form-urlencoded");
let body = new HttpParams();
body = body.set("email", email);
body = body.set("password", password);
return this.http.post<JSON>("http://localhost:80/verify", body, { headers: headers, withCredentials: true, observe: "response" }).pipe(
map(res => {
return res.body;
}),
catchError(this.handleError)
);
}
我一直在通过注释/取消注释一行PHP代码来测试“ XSRF-TOKEN”会话cookie。会话cookie处于活动状态时,会发生此错误。
当我删除cookie时,显然没有这个问题,因为req.clone()
函数永远不会通过,因为不满足条件。
答案 0 :(得分:1)
您的服务器端代码未正确响应XSRF / CSRF工作流程的预检请求。您必须对OPTIONS请求返回“ 200 OK”响应,以便Angular插件可以正常工作:
<?php
$return = array();
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
// instead of doing that in .htaccess
header("Access-Control-Allow-Origin: http://localhost:4200");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Headers: Content-Type");
header("Access-Control-Allow-Headers: Authorization");
header("Access-Control-Allow-Headers: X-XSRF-TOKEN");
header("Access-Control-Expose-Headers: Authorization");
// a 200 OK response to preflight with empty body
header("HTTP/1.0 200");
} elseif (isset($_POST["email"]) && isset($_POST["password"])) {
// presuming all request that are not a preflight
// must be a POST request.
header("HTTP/1.0 200");
$return["msg"] = "random";
echo json_encode($return);
} else {
header("HTTP/1.0 400");
$return["error_message"] = "HTTP Post variables are not set!";
$return["friendly_error_message"] = "Client error!";
echo json_encode($return);
}
exit();