Why isn't my POST Webhook working in Django? - python

I use the app Salesmate and am trying to write a a client on my site that adds features through the API. For this to work I need Salesmate's Webhooks. My client is in Django.
When I send a GET request webhook it makes it into my client.
When I send a POST request webhook it never makes it into the view.
When I send a test POST request from https://reqbin.com/ it makes it into the view and performs as expected.
I've played endlessly with the JSON body and headers. There could still be something I'm missing here, or there could be a flag raised in Django invalidating the sender, or something else...
Here is Salesmate webhook request, in the app. I've played with many headers, and sent requests with and without JSON bodies.
[deleted for privacy]
Here is my django view. Super simple, but it never gets called.
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
#csrf_exempt
def pab(request):
#Do something simple and trackable
return HttpResponse(keep)

I was using the Django module "Moderna" which was causing some issues, still not sure what. I started a naked django app and it started working.

Related

How to send POST request to Flask API employing CSRF token from mobile device (android) app?

Question:
How can I POST data from my android app to my flask web app which is employing CSRF protection?
Background:
I've built a website using Flask, and have protected it from CSRF attacks by globally deploying CSRFProtect(), which comes from the Flask-WTForms package.
I am building a phone app that will allow a user to automatically send data to their account on the Flask database every day.
I can successfully access the Flask API using a GET request from my android app.
I am unable to successfully send a POST request from my android app, unless I turn off global CSRF protection within my Flask API.
My thoughts so far:
Option one - turn off CSRF protection if request is coming from an application.
From reading I understand that CSRF attacks require cookies, which are only generated by browsers, and thus if my request is coming from my app, then I am safe from CSRF attacks and could turn off CSRF protection for a specific URL. BUT, this URL could be accessed by anyone if they were to discover it, so I would need to keep CSRF protection on if the request was coming from a browser, and turn it off if coming from my android app. Is this possible?
Option two - get the CSRF token on my android app.
I don't think that coding the token into my app would be safe, as anyone would be able to download the app and potentially access the code (right?). If that's true, then I would need to somehow get the token from Flask via an authentication process with the Flask app. BUT, how can I send form data to the flask app if CSRF protection is blocking my POST requests?
Please advise. Normally with enough googling I can figure out an answer, but on this I'm stuck!
Thank you!
You have not provided enough information here, but I faced a similar issue when I started learning about flask. So, I think this should be a similar case for you too.
I was creating a simple webhook that would accept POST requests from another application. If I turned CSRF off, POST requests would work, but with CSRF protection turned on, POST requests returned with a 400 status code.
There is a simple way to exempt any views or blueprints in Flask from CSRF protection. We can decorate the route that does not need the csrf protection with a flask_wtf.csrf.CSRFProtect.exempt decorator. Please look at the
below code.
from flask import Flask, request, make_response, jsonify
from flask_wtf.csrf import CSRFProtect
app = Flask(__name__) # this will take name of the project
csrf = CSRFProtect()
csrf.init_app(app)
#app.route#app.route("/newhook", methods=['GET', 'POST'])
#csrf.exempt #this will exempt the csrf for this view
def newhook():
if request.method == 'POST':
alldata = request.get_json()
resp = alldata['message']
num = alldata["from"]
myres = make_response(jsonify(resp, num))
return myres
I am also providing a link to the official flask_wtf CSRF protect documentation below for reference.
https://flask-wtf.readthedocs.io/en/0.15.x/csrf/#exclude-views-from-protection
Hope this helps!!

Django REST: OPTIONS request is registered as PUT

Whenever the browser sends an OPTIONS request, Django REST registers that as a PUT request.
I was writing my permission code when I noticed it. I use the default request parameter that is passed into the def has_object_permission( self, request, view, obj ):.
Using request.method will return the correct request method for every request except for OPTIONS.
However, when I use request.method in a my get_permission( self, request, view ): function in a different part of the project, correct response is returned. Could there be something wrong with the has_object_permission() function?
Currently I just check if the request is PUT, as I believe PUT requests are not used by Django anyway. But it would be nice if I could use the actual name instead.
My Django REST version is 3.9.0
OPTIONS requests are often used for what are called "pre-flight" requests in Cross-origin resource sharing (CORS). This is not anything wrong with has_object_permission(), it's just that these pre-flight requests are probably not intended to handled by your view. There is a more detailed answer in this SO post: https://stackoverflow.com/a/29954326/784648

How to get Twilio's RequestValidator to work

I'm not sure why this doesn't work. I have been looking at Twilio's documentation here, and I tried just making it a function call, but that didn't work, so I put it directly in my view, and it still didn't work. It always returns 403.
I have verified that my auth token is the same as what is on Twilio as well.
from braces.views import CsrfExemptMixin
from django.http import HttpResponse, HttpResponseForbidden
from twilio.util import RequestValidator
from secretphone.settings import TWILIO_AUTH_TOKEN
class SMSWebhook(CsrfExemptMixin, View):
def post(self, request):
validator = RequestValidator(TWILIO_AUTH_TOKEN)
request_valid = validator.validate(
request.build_absolute_uri(),
request.POST,
request.META.get('HTTP_X_TWILIO_SIGNATURE', '')
)
if not request_valid:
return HttpResponseForbidden()
So that nobody has the same problem I did, and no answer, apparently ngrok's https URL does not get passed through to django. My problem was that my webhook was passed using ngrok's https link, but when it got to my app, it changed to an http link. My guess is that request.build_absolute_uri() gets the protocol from django(webserver) itself, which uses http as the protocol.
So anyone having this problem while using ngrok, make sure you are not using the https link.

How to pass CSRF token between django applications by reading it from request using urllib

How to pass CSRF token between Django applications by reading it from request using urllib.
I am having two servers running with Django applications, based on URL need to send request to other server and give the response back.
Django middelware either returns None or Response.
In case of None: it processes request on same server.
In case of Response: it sends the response bake to client and bypassing request to same server.
Say I have two servers "S1" and "S2", and for URL ("/user/1/profile") I have to send request to "S2".
I am doing request cloning in django middleware which checks the matching URL and makes https request(using urllib) with all cookies and headers to "S2" server and sending response back by converting it from urllib-response to django-response.
With "GET" requests its working fine, but I am getting "403 CSRF" with "POST" requests.
Any suggestions what I am missing here.
As I understand you are building a REST api.
The DjangoCSRF Token is browser dedicated.
You can disable the DjangoCsrf Protection by adding the csrf_exempt decorator
From the docs:
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
#csrf_exempt
def my_view(request):
return HttpResponse('Hello world')
But you should consider using the Django Rest Framework And it's Authentication Methods for improved security.

Adding csrf_token to my post request from iPhone app

I have an iPhone application from which I would like to call a post service passing parameters in its request, doing so caused a server error 500.
I have read Django documentation here and I still haven't figure out how to get a csrf_token and how to add it to the AFNetworking AFHTTPRequestOperationManager POST method.
On the server side I've added django.middleware.csrf.CsrfViewMiddleware in the MIDDLEWARE_CLASSES section, but it doesn't seem to do the trick.
My view looks like this; I am not doing much, just hoping to pass.
from django.core.context_processors import csrf
from django.shortcuts import render_to_response
def foo(request):
c={}
c.update(csrf(request))
if request.method == 'POST':
return HttpResponseRedirect("Post received");
The Django CSRF Middleware uses cookies and forms and whatnot to send a code to the page, then make sure the correct page is the one sending information back. In both cases, you must do a GET request to the server, and if you have the middleware installed correctly, it will put the CSRF token into a cookie for you.
Check out the documentation for more info on this.
Now, I noticed you're using a library that uses NSURLConnection, so that should handle cookies for you. I got this bundle of code (untested) that lets you pull the cookie name that you specify in your settings file (again, check out the documentation link above) then put that in your POST.
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL: networkServerAddress];
for (NSHTTPCookie *cookie in cookies)
{
// get the right cookie
}
Of course, if you're only making POSTs and never GETs first, you don't have a CSRF token to send!
And that's why we have the #csrf_exempt tag. (Docs here) This is the way to go 99% of the time, since most apps you won't do a GET before you do a POST. (in webpages you have to do a GET first). Note that this is intended only when an app is sending only POSTs and there's no session to speak of. You really need to think about your own security when using this, and how you verify that a given app/user really is who they claim to be. And how you disable people from hitting this URL from a webbrowser.
TLDR: Probably use #csrf_exempt on the view, but be careful.

Categories