I used requests to send request.
import requests
def print(req):
print('{}\n{}\n{}\n\n{}'.format(
'-----------START-----------',
req.method + ' ' + req.url,
'\n'.join('{}: {}'.format(k, v) for k, v in req.headers.items()),
req.body,
))
print "----------END------------"
try:
req = requests.Request('GET',
'https://myip/myproject/upload/token',
headers={'Authorization': 'Token 401f7ac837a',
})
prepared = req.prepare()
print(prepared)
except Exception as e:
print "Exception:", e
Output:
-----------START-----------
GET https://myip/myproject/upload/token
Authorization: Token 401f7ac837a
None
----------END------------
But after I printed the request.META, there is
META:{u'CSRF_COOKIE': u'YGzoMaNEQJz1Kg8yXAwjJt6yNuT9L'
What set the CSRF_COOKIE?
Any comments welcomed. Thanks
UPDATE
(1)
From the doc, it said This cookie is set by CsrfViewMiddleware, which means the CSRF cookie was set in back-end and set to front-end in the response (CSRF cookie: server -> browser). Why it also said For all incoming requests that are not using HTTP GET, HEAD, OPTIONS or TRACE, a CSRF cookie must be present? And why it appears in my request.META? (CSRF cookie: browser -> server ???)
(2)
It said **A hidden form field with the name ‘csrfmiddlewaretoken’ present in all outgoing POST forms. The value of this field is the value of the CSRF cookie.
This part is done by the template tag.
**
When and How the template tag do it?
This is a standard cookie Django applications spin up for each new user to prevent Cross Site Forgery.
A CSRF cookie that is set to a random value (a session independent
nonce, as it is called), which other sites will not have access to.
This cookie is set by CsrfViewMiddleware. It is meant to be permanent,
but since there is no way to set a cookie that never expires, it is
sent with every response that has called
django.middleware.csrf.get_token() (the function used internally to
retrieve the CSRF token).
For security reasons, the value of the CSRF cookie is changed each
time a user logs in.
for more reading
https://docs.djangoproject.com/en/1.9/ref/csrf/#how-it-works
Related
I'm trying to test out Anti Forgery tokens with API calls using VS2019 (C#) and RestSharp. What i'm doing is doing a GET to our login page to get 4 tokens/ cookies, then attaching these to a POST, with the Username and password, to try to log on. The first call succeeds and gives me a HTTP 200 and 4 cookies/ tokens back (ASP.NET_SessionId, XSRF-TOKEN, XSRF-COOKIE and a __RequestVerificationToken - all get attached as cookies (in the cookiecontainer) to the POST API call), the 2nd call however, fails with an HTTP 500 with this message: "Validation of the provided anti-forgery token failed. The cookie "__RequestVerificationToken" and the form field "__RequestVerificationToken" were swapped.". I'm including this token twice in my POST call - once as a cookie and once as part of the request body. Here is my code - can anyone shed any light on how to fix this error?
Thanks,
Jamie.
public void LogIn(string userName, string password)
{
// 1st call to get the cookies and tokens.
CommonProperties.Client = new RestClient { CookieContainer = new CookieContainer() };
CommonProperties.Client.BaseUrl = new Uri($"https://localhost:50000/Account/Login");
var request = new RestRequest(Method.GET);
request.AddParameter("ReturnUrl", "%2F", ParameterType.QueryString);
CommonProperties.Response = CommonProperties.Client.Execute(request);
CommonProperties.Client.BaseUrl = new Uri($"https://localhost:50000/Account/Login");
var requestToken = CommonProperties.Response.Cookies.Single(c => c.Name ==
"__RequestVerificationToken");
// 2nd call to log in.
request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Accept-Encoding", "gzip, deflate, br");
request.AddHeader("Accept", "*/*");
request.AddHeader("Referer", $"https://localhost:50000/Account/Login");
request.AddParameter("undefined", $"__RequestVerificationToken=
{requestToken.Value}&UserName=userName&Password=password_321", ParameterType.RequestBody);
CommonProperties.Response = CommonProperties.Client.Execute(request);
}
I just solved this issue myself, so hopefully this answer helps anyone else who comes looking.
When you originally load the page with the GET it will return the cookie with the name of __RequestVerificationToken PLUS a form field with the same name. That form field will have a different value to the cookie's value, and in your POST you must set the body field for __RequestVerificationToken to have that form field's value, and the value of the cookie with the same name must match the cookie from the GET response.
If you have the same value for both the form field and the cookie, you get that rather misleading error that suggests the values are "swapped". They are not actually swapped, they're just matching, which is incorrect.
As I see from the answer for this question: Karate will automatically send any cookies returned by the server in the next request.
But when I send the request I see two sets of cookies in Set-Cookie of response: one is auto-created and another is real, that returned from the server.
When I printed responseCookies, I saw there only automatic cookies
and for the next request new cookies are generated and sent.
For my test I need to use cookies returned after the first request because it is a call to login service.
Feature: Using cookies in next request
Background:
Given url baseUrl
And path LOGOUT_SERVICE_ENDPOINT
And configure headers = read('classpath:headers.js')
And def filename = 'classpath:resources/users/' + brand.toLowerCase() + '/user.json'
And json user = read(filename)
Scenario: Login
When def login = callonce read('classpath:features/login_service/login.feature') user
* print login.responseCookies
And request { arg1: '#(brand)'}
And method post
Then status 200
What is wrong in my feature or it is Karate issue?
two sets of cookies in Set-Cookie of response:
Maybe that is a bug in the server ?
Also try using "shared scope", because cookies also will be part of the "global" variables etc.
* callonce read('classpath:features/login_service/login.feature') user
* request { arg1: '#(brand)'}
If you are still stuck, please follow this process: https://github.com/intuit/karate/wiki/How-to-Submit-an-Issue
I'm attempting to retrieve an authentication cookie from a POST sign-in request. When I send this request using Postman, I see the cookie's value in the Cookies tab of the response in Postman.
Postman Response Cookies
My current Lua script is as follows:
local signInUrl = webBaseUrl.."/signin"
local signInResponse = http.request({"POST", signInUrl, headers={
["Content-Type"]="application/x-www-form-urlencoded",
["Referer"] = baseUrl}, data="UrlHash=&UserName="..username.."&Password=123&RememberMe=false", auto_decompress=true})
for i,v in pairs(signInResponse.cookies) do print(i,v) end
Printing out the value of the cookies returns a sessionId cookie and a return email cookie, but not the authentication cookie that I'm looking for.
I can see that the authentication cookie that I'm looking for is actually located in the Request Headers, in the Postman Console.
Postman Console
How would I go about getting the value of this cookie?
Using django.contrib.auth.views.login() to process user logins I'm seeing 403 responses in a production environment. A second attempt to login succeeds after an initial 403 (when that response occurs).
I've begun to log all 403 login failures, capturing the POST payload and cookie values which shows that csrfmiddlewaretoken (the hidden form field value) and csrftoken (cookie value) don't match. It's intermittent and happens to many users.
The following decorators are all applied to the login function being used to proxy the django.contrib.auth.views.login() function: #ensure_csrf_cookie, #sensitive_post_parameters, #csrf_protect, #never_cache
What might be the causes of this problem?
The CSRF token is rotated after login.
If you open the login page in one tab, login using a second tab, then you'll get a CSRF error if you submit the form on the original tab.
Trying to learn about security. Curious about why in django when
submitting a form (a POST), there are 2 separate "elements" that
contain the same csrf token value:
- the csrftoken cookie:
COOKIES:{'csrftoken': '1effe96056e91a8f58461ad56c0d4ddc', ...
- the Form's hidden csrfmiddlewaretoken:
POST:<QueryDict: {u'csrfmiddlewaretoken':
[u'1effe96056e91a8f58461ad56c0d4ddc'], ...
If django is inserting the hidden csrf field/value to
the form when it sends it to the browser (GET), and expects the
same value back when receiving the POST, then why is it
necessary to also set a cookie?
A more general question, if either of them was missing (form, cookie),
could you provide a scenario that explains how this could be exploited
(security attack)?
By the way, I ran a couple of simple tests to make sure that
django was checking the validity of each one separately and
indeed it is:
if I change the form's csrf value before doing the POST,
I get this debug error back:
CSRF token missing or incorrect
if I delete the csrf cookie before doing the POST,
I get a different error back:
CSRF cookie not set.
I'm just familiar with basic csrf concepts and want to
learn how django helps protect against these types of attacks.
Thanks,
jd
update:
Although both answers (S.Lott and M. DeSimone) were informative and
make sense, I thought that there could be a more detailed explanation
for requiring the presence of the security value in both the form and
in the cookie. While searching outside stackoverflow.com, I came across
a blog post from...Jeff Atwood.
I have included a third answer (sorry to answer my own question but
I think that it is relevant supplemental info) that refers to a blog
post from Jeff and includes a quotation.
From Jeff Atwood's blog entry:
Preventing CSRF and XSRF Attacks
(Oct 14, 2008)
The original post
The Felten and Zeller paper (pdf) recommends the "double-submitted
cookie" method to prevent XSRF:
When a user visits a site, the site should generate a
(cryptographically strong) pseudorandom value and set it as a
cookie on the user's machine. The site should require every form
submission to include this pseudorandom value as a form value and
also as a cookie value. When a POST request is sent to the site,
the request should only be considered valid if the form value and
the cookie value are the same. When an attacker submits a form on
behalf of a user, he can only modify the values of the form. An
attacker cannot read any data sent from the server or modify cookie
values, per the same-origin policy. This means that while an
attacker can send any value he wants with the form, he will be
unable to modify or read the value stored in the cookie. Since the
cookie value and the form value must be the same, the attacker will
be unable to successfully submit a form unless he is able to guess
the pseudorandom value.
The advantage of this approach is that it requires no server state;
you simply set the cookie value once, then every HTTP POST checks to
ensure that one of the submitted values contains the exact
same cookie value. Any difference between the two means a possible
XSRF attack.
The cookie is there for AJAX support. Quoting the Django docs:
While the above method can be used for AJAX POST requests, it has some inconveniences: you have to remember to pass the CSRF token in as POST data with every POST request. For this reason, there is an alternative method: on each XMLHttpRequest, set a custom X-CSRFToken header to the value of the CSRF token. This is often easier, because many javascript frameworks provide hooks that allow headers to be set on every request. In jQuery, you can use the ajaxSend event as follows:
$('html').ajaxSend(function(event, xhr, settings) {
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
});
Adding this to a javascript file that is included on your site will ensure that AJAX POST requests that are made via jQuery will not be caught by the CSRF protection.
They spot two different problems.
Cookie is to authenticate the client machine making the connection.
The hidden form field is to authenticate the source of the form.
Example Scenario: User A, on the client machine could bookmark the form. User B logs on, gets a valid cookie from today. User A could submit the invalid form field from yesterday when the browser has a left-over cookie from user B's session.
what client/browser resources are typically compromised,
None.
and how is it that these csrf fields help protect us from the forgery requests?
The CSRF tokens establish identity.
One (and only one) browser has a CSRF cookie token. But that browser could have multiple copies of a site open or bookmarked forms.
One (and only one) page form on that browser has a CSRF form token.
The browser and form cookies must match to assure one browser/one form.