Django:在没有 CSRF 令牌的情况下重置密码
Django: resetting password without a CSRF token
我有一个管理 Users
. Using the built-in functionality, users can request a password reset from the website and that works great. I have implemented it according to this tutorial so I am using the built-in password reset functionality.
的 Django 网站
我有一个 Android 应用程序,用户应该也可以从中请求重设密码。问题是我没有 CSRF token in the application, and the the built-in password_reset
method has the @csrf_protect
decorator. This means that I cannot access it without a CSRF token and I also can't modify it with the @csrf_exempt 装饰器。
所以下一个想法是创建一个函数,它生成一个 CSRF 令牌,将其存储在请求中并重定向到发送重置电子邮件的正确 URL。问题是 according to this, django does not allow to pass POST parameters further in a redirect.
因此我的问题是如何在没有 CSRF 令牌的情况下在 Django 中请求重设密码?或者,从应用程序请求此请求的正确方法是什么?
我自己找到了解决办法。请随时 post 任何替代解决方案。一个不需要两个单独请求的会特别好。
如果您查看 the password_reset method,您会发现如果请求方法是 POST,它只会尝试将请求作为重置请求进行处理。否则它只是 returns 一个 TemplateResponse
包含一个表单。这也包含 CSRF 令牌作为 cookie。
首先,我向 http://myaddress.com/user/password/reset/
发送 GET 请求并从响应中提取 CSRF cookie。然后我发送一个 POST 请求,其中包含 cookie、电子邮件地址和 2 headers(见下文)。
这是我从 Android
(修剪):
实现的代码
String url = "http://myaddress.com/user/password/reset/";
GET 请求:
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
CookieStore cookieStore = new BasicCookieStore();
HttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpResponse httpResponse = httpClient.execute(httpGet, localContext);
Cookie csrfCookie = null;
for (Cookie cookie : cookieStore.getCookies()) {
if (cookie.getName() == "csrftoken") {
csrfCookie = cookie;
break;
}
}
if (csrfCookie == null) {
throw new NullPointerException("CSRF cookie not found!");
}
return csrfCookie;
请注意,您需要 org.apache.http.client
中的 CookieStore
。
POST 请求:
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost(url);
// Prepare the cookie store to receive cookies.
CookieStore cookieStore = new BasicCookieStore();
cookieStore.addCookie(csrfCookie);
httpPost.setHeader("Referer", url);
httpPost.setHeader("X-CSRFToken", csrfCookie.getValue());
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addTextBody("email", emailAddressToReset);
httpPost.setEntity(builder.build());
HttpResponse httpResponse = httpClient.execute(httpPost, localContext);
if (httpResponse.getStatusLine().getStatusCode() != 200) {
throw new Exception("Could not reset password!");
}
Toast.makeText(context, "Password reset requested! Please check your email inbox!", Toast.LENGTH_LONG).show();
我有一个管理 Users
. Using the built-in functionality, users can request a password reset from the website and that works great. I have implemented it according to this tutorial so I am using the built-in password reset functionality.
我有一个 Android 应用程序,用户应该也可以从中请求重设密码。问题是我没有 CSRF token in the application, and the the built-in password_reset
method has the @csrf_protect
decorator. This means that I cannot access it without a CSRF token and I also can't modify it with the @csrf_exempt 装饰器。
所以下一个想法是创建一个函数,它生成一个 CSRF 令牌,将其存储在请求中并重定向到发送重置电子邮件的正确 URL。问题是 according to this, django does not allow to pass POST parameters further in a redirect.
因此我的问题是如何在没有 CSRF 令牌的情况下在 Django 中请求重设密码?或者,从应用程序请求此请求的正确方法是什么?
我自己找到了解决办法。请随时 post 任何替代解决方案。一个不需要两个单独请求的会特别好。
如果您查看 the password_reset method,您会发现如果请求方法是 POST,它只会尝试将请求作为重置请求进行处理。否则它只是 returns 一个 TemplateResponse
包含一个表单。这也包含 CSRF 令牌作为 cookie。
首先,我向 http://myaddress.com/user/password/reset/
发送 GET 请求并从响应中提取 CSRF cookie。然后我发送一个 POST 请求,其中包含 cookie、电子邮件地址和 2 headers(见下文)。
这是我从 Android
(修剪):
String url = "http://myaddress.com/user/password/reset/";
GET 请求:
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
CookieStore cookieStore = new BasicCookieStore();
HttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpResponse httpResponse = httpClient.execute(httpGet, localContext);
Cookie csrfCookie = null;
for (Cookie cookie : cookieStore.getCookies()) {
if (cookie.getName() == "csrftoken") {
csrfCookie = cookie;
break;
}
}
if (csrfCookie == null) {
throw new NullPointerException("CSRF cookie not found!");
}
return csrfCookie;
请注意,您需要 org.apache.http.client
中的 CookieStore
。
POST 请求:
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost(url);
// Prepare the cookie store to receive cookies.
CookieStore cookieStore = new BasicCookieStore();
cookieStore.addCookie(csrfCookie);
httpPost.setHeader("Referer", url);
httpPost.setHeader("X-CSRFToken", csrfCookie.getValue());
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addTextBody("email", emailAddressToReset);
httpPost.setEntity(builder.build());
HttpResponse httpResponse = httpClient.execute(httpPost, localContext);
if (httpResponse.getStatusLine().getStatusCode() != 200) {
throw new Exception("Could not reset password!");
}
Toast.makeText(context, "Password reset requested! Please check your email inbox!", Toast.LENGTH_LONG).show();