With #csrf_exempt still have Set-Cookie: csrftoken - django

With Django 1.8, I do not want to have a cookie set on the homepage of my site when the users are not logged in. So I decorate my view with #csrf_exempt like
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def mainhome(request):
When I look at the query I can see the cookie still set, why ?
rodo#roz-desktop:~/(master)$ curl -I http://127.0.0.1:8000/
HTTP/1.0 200 OK
Date: Sat, 13 Jun 2015 08:59:27 GMT
Server: WSGIServer/0.1 Python/2.7.8
Content-Type: text/html; charset=utf-8
Vary: Cookie
X-QueryInspect-Duplicate-SQL-Queries: 2
X-QueryInspect-Total-SQL-Time: 34 ms
X-QueryInspect-Total-Request-Time: 283 ms
X-QueryInspect-Num-SQL-Queries: 3
Set-Cookie: csrftoken=sa5x0DyxgBamca0D84ZZnzl2WAL0evkv; expires=Sat, 11-Jun-2016 08:59:27 GMT; Max-Age=31449600; Path=/

As #Daniel Roseman indicated, #csrf_exempt will not help you with that.
The middleware responsible for the session cookie is SessionMiddleware. You can read more about it in the Django Docs: How to use sessions. Unfortunately, there is no similar decorator in order to exempt some specific view.
So in order to customize the middleware's behaviour, you would need to inherit from SessionMiddleware. There is a nice answer on the matter on SO.

csrf_exempt controls whether or not CSRF is enforced on POST. It has nothing to do with whether or not the CSRF cookie is set; that is done by the CsrfViewMiddleware for all responses.

Related

Samesite=Strict cookies are not included in 302 redirects when user clicks link from a different domain

A customer will link to one of our webpages on their site: customer.site/links.html
A person clicks that link and gets sent to our.site/webapp/handlerequest.aspx?someparam=somevalue
The value of someparam is set in a cookie with SameSite=Strict and then uses a 302 redirect to another page on the same domain:
Request URL: https://our.site/webapp/handlerequest.aspx?someparam=somevalue
Request Method: GET
Status Code: 302
Remote Address: ...
Referrer Policy: strict-origin-when-cross-origin
cache-control: private
content-length: ...
content-type: text/html; charset=utf-8
date: ...
location: /webapp/someotheraction
server: Microsoft-IIS/10.0
set-cookie: someparam=somevalue; expires=Thu, 17-Mar-2022 14:41:13 GMT; path=/; secure; HttpOnly; SameSite=Strict
strict-transport-security: max-age=31536000
x-frame-options: SAMEORIGIN
The browser does NOT include this cookie on the 302 redirect to /webapp/someotheraction.
This only starting happening when we specifically change our code to set this cookie to SameSite=Strict.
This occurs in Chrome, Firefox, Edge, and IE (old IE)
Is this on purpose? Why? Since we are going from one request on the domain to another request in the same domain, shouldn't the SameSite=Strict cookies be included? Does this have anything to do with the referer policy defaulting to strict-origin-when-cross-origin? https://www.w3.org/TR/referrer-policy/ doesn't say anything about cookies
This is a cross-site request because the initial navigation was cross-site (from customer.site to our.site). Strict cookies are never sent on cross-site requests. It doesn't matter that the request gets redirected (in this case, to another URL on our.site), just the fact that the user clicked on a cross-site link means the request is cross-site.
As for why this is the case, it's because the origin responsible for initiating the navigation is important in preventing cross-site request forgery (CSRF). Imagine if https://evil.site had a link to https://bank.site/transfer-funds which redirects to https://bank.site/transact. We wouldn't want Strict cookies to be send to the /transact endpoint after the redirect, even if it was redirected to by the same site, because the initiating origin is cross-site.

Django Cookie Prefix to pass securityheaders.com

securityheaders.com fails my configurations with the following error:
Set-Cookie There is no Cookie Prefix on this cookie.
And this is the value of the cookie:
Set-Cookie sessionid=123456789123456789123456789; expires=Thu, 12 Sep 2019 06:51:38 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Strict; Secure
I have tried to add the cookie prefix with in settings.py:
CSRF_COOKIE_NAME = '__Secure-csrftoken'
But it seems to be a different paramater. I have search the documentation and that is all I could find, and seems to not be applicable.
securityheaders.com on cookie prefixes states that it needs to start with __Secure- or __Host-
You used the wrong setting, this is not the CSRF_COOKIE_NAME [Django-doc], but the SESSION_COOKIE_NAME [Django-doc]:
Default: 'sessionid'
The name of the cookie to use for sessions. This can be whatever you want (as long as it’s different from the other cookie names in your application).
Note that the name of the cookie it complains about is sessionid:
Set-Cookie sessionid=123456789123456789123456789; expires=Thu, 12 Sep 2019 06:51:38 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Strict; Secure
So you need to specify this as:
SESSION_COOKIE_NAME = '__Secure-sessionid'
CSRF_COOKIE_NAME = '__Secure-csrftoken'

query a webpage for variable entity using a consistent URL structure

Would someone please help me to understand how I might inject into my program a query to this webpage?
There are two parameters that need to be set, i.e.
"Site:", is where you enter the language and site code.
&
"Page:", you must put in the exact title of the page as it appears on the connected site.
The URL's always look like this:
https://www.wikidata.org/wiki/Special:ItemByTitle?site=en&page=Mikhail+Bakunin&submit=Search
https://www.wikidata.org/wiki/Special:ItemByTitle?site=en&page=Thomas+Edward+Lawrence&submit=Search
and the language is always English, so you see, it's just:
https://www.wikidata.org/wiki/Special:ItemByTitle?site=en&page=Blah+Blah&submit=Search
The objective of querying that page is to retrieve the ID value associated with the page, so for Mikhail Bakunin it's Q27645 and for T. E. Lawrence it's Q170596
It becomes part of the URL once the page is reached:
https://www.wikidata.org/w/index.php?title=Q170596&site=en&page=Thomas+Edward+Lawrence&submit=Search
But also maybe I could strip it from the page, using beautifulSoup or soemthng?(that's a guess)
The program needs to be generalizable, which is to say, that the name of the entity we're searching for is variable, it will change in the program, so that needs to be taken in account.
I guess using python or php or something would not be a crime against humanity if it's easier, though I prefer java.
update:
import java.net.*;
import java.io.*;
public class URLConnectionReader
{
public static void main(String[] args) throws Exception
{
URL site = new URL("https://www.wikidata.org/wiki/Special:ItemByTitle?site=en&page=Mikhail+Bakunin&submit=Search");
URLConnection yc = site.openConnection();
BufferedReader in = new BufferedReader(
new InputStreamReader(
yc.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
}
this works sort of, but the result is quite messy.
I guess I could grab it out of this thing:
<!-- wikibase-toolbar --><span class="wikibase-toolbar-container"><span class="wikibase-toolbar-item wikibase-toolbar ">[<span class="wikibase-toolbar-item wikibase-toolbar-button wikibase-toolbar-button-edit">edit</span>]</span></span>
but how?
When you request this URL the response is:
HTTP/1.1 302 forced.302
Server: Apache
X-Powered-By: HHVM/3.3.1
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Vary: Accept-Encoding,X-Forwarded-Proto,Cookie
X-Content-Type-Options: nosniff
Location: http://www.wikidata.org/w/index.php?title=Q27645&site=en&page=Mikhail+Bakunin&submit=Search
Content-Type: text/html; charset=utf-8
X-Varnish: 1641959068, 1690824779, 1606045625
Via: 1.1 varnish, 1.1 varnish, 1.1 varnish
Transfer-Encoding: chunked
Date: Fri, 17 Apr 2015 11:49:55 GMT
Age: 0
Connection: keep-alive
X-Cache: cp1054 miss (0), cp3003 miss (0), cp3013 frontend miss (0)
Cache-Control: private, s-maxage=0, max-age=0, must-revalidate
Set-Cookie: GeoIP=NL:XXX:51.4400:5.6194:v4; Path=/; Domain=.wikidata.org
So there's a 302 redirect in the HTTP response headers. That's where you'll want to grab your Q-number. Simlpy regex it out of the Location header with a regex like:
^Location:.*?title=(Q[0-9]+)
...and use matchgroup 1 (should be Q27645).
To grab the HTTP headers, have a look at this page; it basically goes like:
URL obj = new URL("https://www.wikidata.org/wiki/Special:ItemByTitle?site=en&page=Mikhail%20Bakunin&submit=Search");
URLConnection conn = obj.openConnection();
//get header by 'key'
String location = conn.getHeaderField("Location");
//TODO: Regex here

Django/DRF - 405 Method not allowed on DELETE operation

I'm working with two dev servers on my local machine (node & django's).
I've added django-cors-headers to the project to allow all origins & methods (on dev) with the following settings :
CORS_ORIGIN_ALLOW_ALL = 'ALL'
CORS_ALLOW_METHODS = (
'GET',
'POST',
'PUT',
'PATCH',
'DELETE',
'OPTIONS'
)
I'm getting 405 when attempting DELETE.
Looking at the response headers
HTTP/1.0 405 METHOD NOT ALLOWED
Date: Mon, 03 Nov 2014 10:04:43 GMT
Server: WSGIServer/0.1 Python/2.7.5
Vary: Cookie
X-Frame-Options: SAMEORIGIN
Content-Type: application/json
Access-Control-Allow-Origin: *
Allow: GET, POST, HEAD, OPTIONS
Notice that DELETE & PATCH / PUT are not present in the allowed methods list.
Is there something missing from my configuration ?
The response looks very similar to that of the list view (/api/resource/) for a ViewSet. List views only support GET, to list all of the objects, and POST to create a new object.
DELETE requests are only allowed on the detail view (/api/resource/1/). This is because Django REST Framework needs to know what object you are looking to delete, and this information cannot be retrieved from just the list view.
If you need to connect http method DELETE with URL without pk in DRF try this inside of your ModelViewSet:
#action(methods=['delete'], detail=False)
def delete(self, request):
# your code
UPD: Note that action attribute inside of ModelViewSet class will be None due request. If you check it somewhere, handle not only action name, but request method and request path.

Cors issues with angular dart - cookies not set

I work on a app using angular.dart at the clientside and dart in the serverside.
I have write a login rest entrypoint and want to set cookies the header was in the response but the cookies are not set.
set-cookie:app-user=533c1470a2658184a7625d7d; Expires=Tue, 8 Apr 2014 9:15:47 GMT; Domain=.ballr.eu; Path=/
set-cookie:app-tokn=530fa71b615e168787a7cb5b5c589a5601065e1e3f921d4b770c784394de3a42; Expires=Tue, 8 Apr 2014 9:15:47 GMT; Domain=.ballr.eu; Path=/
I try to check my headers or my value set in cookies, but to my mind is good
headers :
request.response..statusCode=HttpStatus.OK
..headers.set(HttpHeaders.CONTENT_TYPE, 'text/plain: charset=UTF-8')
..headers.add("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PUT, DELETE")
..headers.add("Access-Control-Allow-Headers", "origin, x-requested-with, content-type, accept")
..headers.add("Access-Control-Allow-Origin", "*");
cookies :
static setCookie(HttpRequest request, String key, String value, DateTime duration) =>
request.response.cookies.add(new Cookie(key, value)..path = '/'
..expires = duration
..domain = '.app.eu');
I follow some threads on stackoverflow and google groups and I think it's a problem of "withCredientals" a value I have set in an another projet (angular/Java) but I don't find this parameter on angular.dart.
Can you help me to find it or have you somes ideas?
Thank you for your help/time
I'm not sure if I understand you question correctly but maybe this is what you are looking for:
(on the client)
var request = new HttpRequest()
..open("POST", uri.toString(), async: true)
..withCredentials = true // seems to be necessary so that cookies are sent
EDIT
I missed that this is about Angular. This needs a slightly different approach.
If you use the Angular http service you have a parameter
class MyController {
Http _http;
MyController(this._http) {
_http.getString('someurl', withCredentials: true).then((e) => ...);
// or _http.request('someurl', method: 'POST', withCredentials: true).then((e) => ...);
}
}