I am sending a POST request from an iOS client
-(void)loadFavorite:(NSArray*)favorites{
//data and url preparation
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"https://example.com" forHTTPHeaderField: #"Referer"];
[request setValue:[NSString stringWithFormat:#"%tu", [requestData length]] forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody: requestData];
if ([Tools isNetWorkConnectionAvailable]) {
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
//response handle
}
}
Here is the response :
<div id="summary">
<h1>Forbidden <span>(403)</span></h1>
<p>CSRF verification failed. Request aborted.</p>
</div>
I'm using Flask framework and pythonanywhere for hosting.
It works fine when I reload the python script but after few hours/days the CSRF verification failed error reappear.
Even if I try to disable the CSRF verification in my app.py with :
app.config['WTF_CSRF_CHECK_DEFAULT'] = False
App.py script :
//some import error handlers ...
app = Flask(__name__)
app.config['WTF_CSRF_CHECK_DEFAULT'] = False
#app.route('/api/favorites', methods=['POST'])
def get_favorites_beaches():
if not request.json or not 'favorite' in request.json:
abort(400)
//data process
if __name__ == '__main__':
app.run(host='0.0.0.0',debug=True)
How can I implement the CSRF verification correctly or how to disable it ?
PythonAnywhere developer here, reposting what we just put on our forums. This turned out to be a fairly obscure problem on our hosting platform, and we've just pushed a system patch that fixes it.
Here's what it was: if a web app was shut down for some reason (system reboot, certain kinds of glitch, excessive resource usage, maybe hibernation) then only a GET request would wake it up. POST requests, in particular, would be rejected with a CSRF error (generated by our code that's meant to start up the web app), and the app wouldn't be woken up. So if your app is one that processes mostly POST requests, you'd see this problem. This definitely seems to fit the issue as you describe it.
Our new code wakes up the app when a POST is received. One slight issue remains -- the first POST request that wakes it up will receive a "503 Service Unavailable" response with the "retry-after" header set to "5". If you handle this and do the retry, then the next request will work. We believe that browsers do that automatically, but unfortunately the requests library doesn't by default.
you have a line in your code that is [request setValue:#"https://example.com" forHTTPHeaderField: #"Referer"];
did you not set it to the correct url? A wrong referer is one way you would get a cross site error.
Conrad
Related
Hi I've been scrambling the web for hours now trying to find a solution.
I'm trying to make a post request to my own web server hosted by Namecheap.
Here's my Ajax code to call the Post request. Note: I can't show the url sorry.
$.ajax({
url: "https://api.someurl.com/something" + avariable + "/" + anotherthing,
type: "POST",
crossDomain: true,
dataType: "json",
success: function (response) {
var resp = JSON.parse(response)
console.log(resp)
},
error: function (xhr, status) {
console.log("error")
}
});
This was a code i got from another stackoverflow post's answer which had the most upvotes. It didn't seem to work. actually all of them didn't work.
I'm calling this ajax from a index.html I have running on my localhost.
And i got this error:
Access to XMLHttpRequest at 'the url i cant show' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Any help would be much appericiated! I've never encountered this issue before and I don't know how to handle it.
Update 1
I have access to the backend server. Its running Flask on Python.
Any ideas how I can enable the CORS thing there?
Also I'm not sure what the origin of this index.html will be. Because I'll be packaging it into an electron js desktop application.
Install flask-cors in your flask app:
pip install -U flask-cors
Then in your code:
from flask import Flask
from flask_cors import CORS, cross_origin
app = Flask(__name__)
cors = CORS(app)
#app.route("/something+avariable/anotherthing")
#cross_origin()
def yourfunction():
Alternatively, add it manually:
def after_request(response):
header = response.headers
header['Access-Control-Allow-Origin'] = '*'
return response
If you need it for development only then you can use a CORS browser extension such as this for Chrome and this for FireFox.
CORS stands for Cross Origin Resource Sharing.
Its just a mechanism to block unauthorized request to a server.
On your backend you will have yo authorize the address you are using to access your backend.
For php:
I have a VueJS app running on S3 that is served by a Flask-powered API running on AWS Elastic Beastalk.
The problem
When making some requests, I get the following:
Access to XMLHttpRequest at 'https://api.myflaskapi.net/blueprint/get_info?date=2019-01-01' from origin 'https://app.myvuejsapp.net' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
What I've done so far
In my __init__.py file, initialized by the app factory in Flask I have set CORS(app, support_credentials=True) as the example on this link. With that, I would hope that basically any request would have the CORS heading, so I wouldn't have any policy blocking my frontend requests.
The ideal scenario would be to only allow requests from https://app.myvuejsapp.net, so I tried using CORS(app, support_credentials=True, origins=['https://app.myvuejsapp.net']) but also without success.
I've also tried making one CORS instance for each of my blueprints with CORS(myblueprint) for each .py route file (I have one for each blueprint), also without success.
The strange thing is, I do have one function on Vue that runs when the app is mounted that works just fine. I can't see any difference between this and other functions that won't work.
Example of working function (returns true or false from the backend):
checkDB() {
const path = this.base_url + 'blueprint/check_db'
axios.get(path, this.token)
.then(checkupd => {
this.isupdated = Boolean(checkupd.data);
if (this.isupdated == true) {
this.update_msg = "Database up to date."
this.loading = false
this.finished = true
} else {
this.update_msg = "WARNING: Check DB status."
}
})
.catch(error => {
console.log(error)
})
},
Example of non-working function (returns a XLS from the backend):
getSalesFrom(file) {
const fs = require('fs')
const FileDownload = require('js-file-download');
const path = this.base_url + `blueprint/get_sales?date=${this.date}`
axios.get(path, {
headers:
{
"X-Access-Token": "mytoken",
"Content-Type": "application/json"
},
responseType: 'blob'
})
.then(response => {
const content = response.headers['content-type'];
download(response.data, 'text.xlsx', content)
})
.catch(error => {
console.log(error)
})
this.export_dialog = false
}
S3 CORS Configuration XML
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Authorization</AllowedHeader>
<AllowedHeader>Content-Length</AllowedHeader>
<AllowedHeader>Access-Control-Allow-Origin</AllowedHeader>
<AllowedHeader>X-Access-Token</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Any ideas on what I might be doing wrong?
I've been reading for a while, but can't seem to find a solution for what it seems a pretty simple problem... Maybe I should mess with the S3 bucket permission configuration?
Thanks.
Any time you run into a case where you’re seeing a “No 'Access-Control-Allow-Origin' header is present” message for some requests but not others, use the Network pane in browser devtools to check the HTTP status code of the response.
Almost always what you’re going to find is that the HTTP status code in those cases is a 4xx or 5xx error instead of the expected 200 OK success response.
The only reason you see the “No 'Access-Control-Allow-Origin' header is present” message is those cases is, the Access-Control-Allow-Origin header typically isn’t going to get added to 4xx and 5xx errors. Part of the reason is, in the 5xx case especially, the cause can be a server failure that occurs before the server ever gets around to running your application code. Along with that, most servers by default won’t add application-set response headers to 4xx and 5xx errors; instead by default they only add them to 2xx success responses.
So anyway, what you want to do is, look at the server logs on the server side (for the server you’re sending the request to) and see what messages the server is logging about the cause of whatever problem it is that makes the server end up sending that 4xx or 5xx error response.
As I understand correctly you host your Vue.js application from S3.
You need to include CORS headers in your S3 buckets. Without them the browser will block all requests to your Flask application. You are making requests to api.myflaskapi.net from app.myvuejsapp.net so you need configure CORS in app.myvuejsapp.net.
You can read documentation how to set CORS in S3 here and here.
To configure your bucket to allow cross-origin requests, you create a CORS configuration, which is an XML document with rules that identify the origins that you will allow to access your bucket, the operations (HTTP methods) that will support for each origin, and other operation-specific information.
You can add up to 100 rules to the configuration. You add the XML document as the cors subresource to the bucket either programmatically or by using the Amazon S3 console. For more information, see Enabling Cross-Origin Resource Sharing (CORS).
I'm having issues trying to get a token from my flask-sentinel app with my front-end.
To make the AJAX requests from my front-end to my Python Eve API server I use the superagent module.
While using a Basic Authentication I don't have any issue getting data from my endpoints. See code below:
superagent
.get( 'http://192.168.1.x:5000/endpoint' )
.auth( this.params.username, this.params.password )
.on( 'error', this.onError )
.then( this.onSuccess );
If I try to request a token to the /oauth/token endpoint with this code:
superagent
.post( 'http://192.168.1.x:5000/oauth/token' )
.set( 'Content-Type', 'application/x-www-form-urlencoded' )
.send( 'grant_type=password&client_id='+this.params.client_id+'&username='+this.params.username+'&password='+this.params.password )
.on( 'error', this.onError )
.then( this.onTokenReceived );
I get a CORS error:
Access to XMLHttpRequest at 'http://192.168.1.x:5000/oauth/token' from origin 'http://192.168.1.y:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Here are the settings of my application (omitting the database and domain settings):
SENTINEL_X_DOMAINS = ['http://192.168.1.y:3000']
SENTINEL_X_HEADERS = ['Authorization','Content-type','If-Match','Access-Control-Allow-Origin']
SENTINEL_X_EXPOSE_HEADERS = SENTINEL_X_HEADERS
SENTINEL_RESOURCE_METHODS = ['GET','HEAD','PUT','PATCH','POST','DELETE','OPTIONS']
SENTINEL_PUBLIC_METHODS = SENTINEL_RESOURCE_METHODS
SENTINEL_X_ALLOW_CREDENTIALS = True
X_DOMAINS = ['http://192.168.1.y:3000']
X_ALLOW_CREDENTIALS = True
X_HEADERS = ['Authorization','Content-type','If-Match','Access-Control-Allow-Origin']
RESOURCE_METHODS = ['GET','HEAD','PUT','PATCH','POST','DELETE','OPTIONS']
Can you please guide me in getting what I'm doing wrong?
Thank you in advance!
It's possible that because the content-type is not text/plain, the browser is issuing an OPTIONS request. and as stated in the console error the response does not set the 'Access-Control-Allow-Origin' header.
From looking at Eve's docs, it seems you need to set the X_EXPOSE_HEADERS variable with ['Access-Control-Allow-Origin'] that:
"Allows API maintainers to specify which headers are exposed within a
CORS response. Allowed values are: None or a list of headers names.
Defaults to None."
The browser expects to receive the 'Access-Control-Allow-Origin', thus the failure.
Try to allow this header in the response from the API
In your Flask app, try setting the 'Access-Control-Allow-Origin' header in your response, i.e.,
response.headers.add('Access-Control-Allow-Origin', '*')
That should most likely solve the issue.
I have sorted out how to fix this though I am not completely satisfied.
Here the steps I've followed:
I have forked the Flask Sentinel repository
I have installed Flas-CORS with Pip
I have edited the flask_sentinel/flask_sentinel.py file by importing flask_cors
Before this line I've inserted this piece of code:
CORS(app, origins=['http://192.168.1.y:3000','https://192.168.1.y:3000'])
I went back to my Eve project and installed Flask-Sentinel through my forked repository with Pip instead of the original one
I would like to POST data from my iOS app to my Django server — encoding it all in the URL is just impractical. I want to do this without a form, simply sending JSON data up and getting JSON data out. When I try, I’m running into this error:
Forbidden (CSRF token missing or incorrect.)
For development, I’m currently getting around this by declaring my view method to be #csrf_exempt, but I’m worried that’s unsafe for production. Is it if I’m also declaring the method #login_required?
Assuming it is unsafe, how can I solve this? I understand the approach using {% csrf_token %} in HTML templates -- I’ve used that in other Django apps -- but again, I’m not actually using a form, nor do I wish to. I’m simply encoding my request data in a JSON dictionary, and getting a JSON dictionary back. Here’s the relevant part of the client side:
NSData *data = [NSJSONSerialization dataWithJSONObject:dictWithMyData options:NSJSONWritingPrettyPrinted error:&error];
if (!data) {
if (error)
NSLog(#"NSJSONSerialization error = %#", [error localizedDescription]);
return NO;
}
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:myServerMethodUrl] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:timeout];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:data];
NSURLResponse *urlResponse = nil;
NSData *urlData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error];
if (error) {
NSLog(#"NSURLConnection error = %#", [error localizedDescription]);
return NO;
}
And here’s the relevant server part:
#login_required
def my_server_method(request):
data = simplejson.loads(request.body)
R = {}
# Do stuff with the data here and generate a response with JSON data in R
....
return HttpResponse(json.dumps(R), content_type="application/json")
From what I’ve learned of the CSRF mechanism, the CSRF token is valid for the entire session. So I thought I could make this work by: a) upon authentication, passing the CSRF token to my iOS client, and then b) including the token when I post my data. Here’s how I tried that.
Upon authentication in the server, I find the CSRF token with this and send it to the client:
session_csrf_token = django.middleware.csrf.get_token(request)
And I try to pass it back by modifying my client code above like so. First I augment the data I send with my session_csrf_token (stored as _csrfToken on the client upon login):
NSMutableDictionary *dictCSRF = [NSMutableDictionary dictionaryWithDictionary:dictWithMyData];
[dictCSRF setObject:_csrfToken forKey:#"csrfmiddlewaretoken"];
NSData *data = [NSJSONSerialization dataWithJSONObject:dictCSRF options:NSJSONWritingPrettyPrinted error:error];
Then I augment the request header like so:
[request setValue:_csrfToken forHTTPHeaderField:#"X-CSRF-Token"];
But it’s not working. I get the same "CSRF token missing or incorrect" error.
Any ideas how to get this to work?
I use Ajax Push Engine as push engine and Django for main site. I wrote the server
module which must send the request to my Django-based application when
new user join the channel by using Http module. My Django-based project runs on the local
machine on local.jjjbbb.org.
Ape.addEvent("join", function(user, channel) {
var request = new Http('http://local.jjjbbb.org/test-
this/'); // this is a my test url
request.set('method', 'POST');
request.writeData('test-message', 'Hello APE!');
request.getContent( function(result) {
Ape.log(result); // this code never work
});
});
But this code doesn't work, request doesn't receive. When I change url
to anything else (like www.google.com or localhost for example) all
works correctly and I have a result. But when I try to send request to
my application request doesn't work. This problem is only when I try
to send request from server side, when I use jQuery for sending from
client side all works correctly.
Why I cannot send POST request from server side to my domain?
Sorry, I already found my problem. APE works fine, it was a little trouble with CSRF protection in Django.