How to get data from POST request in Django - django

I spent a lot of time trying to get data from POST request in my django 1.8 application and it doesn't work whatever I do. Hopping that somebody more skillful suggest the solution.
I need to get data from the request:
curl.exe -X POST --data "Status=OK" http://localhost:8000/postback
relevant content of urls.py :
url(r'^postback', 'app.views.process_postback'),
relevant content of views.py :
#csrf_exempt
def process_postback(request):
if request.method == 'POST':
dict = request.POST
print(dict)
return HttpResponse("OK")
I always get empty value in dict :
My question how to get Status from post to inside my app
Here is few more details:
I process postbacks from third party website, so I cannot change content of POST request
I don't need(want) any forms/models for the request, I just need to collect value of Status.
Thanks for help.

I finally figured out what's was wrong. I use VS 2013 with PTVS (Python Tool for Visual Studio) as my development environment. And it appears that if project launched under debugger then http request gets screwed up. If I run project without debugger then everything works fine. I tried to look at the debugger code (C:\Program Files\Microsoft Visual Studio 12.0\Common7\IDE\Extensions\Microsoft\Python Tools for Visual Studio\2.2\visualstudio_py_debugger.py) but didn't find some obvious things that would cause such behavior. If anybody came across it and knows how to fix it would be great to know.

Following the https://superuser.com/questions/149329/what-is-the-curl-command-line-syntax-to-do-a-post-request
Remove -X POST option from Your command
curl.exe --data "Status=OK" http://localhost:8000/postback
Output:
<QueryDict: {u'Status': [u'OK']}>
[04/Dec/2015 21:03:15] "POST /postback HTTP/1.1" 200 2
pip freeze output:
Django==1.8.6

I used django 1.10.so i only can give some advice.when i want to get the value from the form ,no matter GET or POST,i useddict=request.POST.get('dict')
The second 'dict' is your form's input name .Such as in html , it's should be `
<form name="input" method="post">
<input type="text" name="dict" >
<input type="submit" value="submit">
</form>`

Related

Post data to website using Python requests library

I'm trying to make a simple webscaper using Python and the requests library.
r=requests.get(https://nustar.newcastle.edu.au/psp/CS9PRD/EMPLOYEE/HRMS/c/MANAGE_ACADEMIC_RECORDS.STDNT_ACTIVATION.GBL?FolderPath=PORTAL_ROOT_OBJECT.HCSR_RECORDS_AND_REGISTRATION.HCSR_STUDENT_TERM_INFORMATION.HC_STDNT_ACTIVATION_GBL&IsFolder=false&IgnoreParamTempl=FolderPath%2cIsFolder
I would like to POST a search input into this URL, but I'm struggling to work out how.
This is the search box code from the website:
<input id="STDNT_SRCH_EMPLID" class="PSEDITBOX" type="text" maxlength="11" style="width:140px; " value="" tabindex="13" name="STDNT_SRCH_EMPLID"></input>
I assume I have to somehow change value = "" to value = "foo".
Any help will appreciated, thanks.
See request's quick start here.
import requests
value1='foo'
payload = {'STDNT_SRCH_EMPLID': value1} # 'key2': 'value2' and so on (comma delimited)
r = requests.post("http://yourUrl.org/", data=payload)
print(r.text)
Do a network analysis in the developer tool of your browser and copy the curl command of the POST package.
Then you surf to [curl.trillworks.com][1] and convert the curl command by pasting it into a Python POST request.
Inside of your python request you can modify the values.

Django redirect page does not update the view

I'm using the Django Framework on Google App Engine.
I have multiple forms on the same view, to submit to different URL.
Trouble is after I get a form submitted: even if the called method update the datastore and some data, the previous page (where the forms are put in) is not refreshed, showing the updated data.
I could solve this problem using jQuery or some javascrip framework, appending dinamically content returned by the server but, how to avoid it?
Suggestions?
Am I wrong somewhere?
A part of "secure.html" template
<form action="/addMatch" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
Matches:
<br />
{% for m in matches%}
{{m.description}} ---> {{m.reward}}
{% endfor%}
the "/addMatch" URL view:
def addMatch(request):
form = MatchForm(request.POST)
if form.is_valid():
user = User.all().filter('facebookId =', int(request.session["pbusr"]))
m = Match(user=user.get(),description =form.cleaned_data["description"],reward=form.cleaned_data["reward"])
m.save()
return HttpResponseRedirect("/secure/")
else:
logging.info("Not valid")
return HttpResponseRedirect("/secure")
The view method whose seems not working:
#auth_check_is_admin
def secure(request):
model={}
user = User.all().filter('facebookId =', int(request.session["pbusr"]))
u = user.get()
if (u.facebookFanPageId is not None and not u.facebookFanPageId == ""):
model["fanPageName"] = u.facebookFanPageName
model["form"] = MatchForm()
model["matches"] = u.matches
else:
....
return render(request,"secure.html",model)
Francesco
Based on what you posted, it seems like you're redirecting properly and are having database consistency issues. One way to test this would be to look at the network tab in the Google Chrome developer tools:
Click on the menu icon in the upper right
Click on "Tools"
Click on "Developer Tools"
Click on "Network" in the thing that opened up at the bottom of the screen.
Now, there will be a new entry in the network tab for every request that your browser sends and every response it receives. If you click on a request, you can see the data that was sent and received. If you need to see requests across different pages, you might want to check the "Preserve log" box.
With the network tab open, go to your page and submit the form. By looking at the network tab, you should be able to tell whether or not your browser issued a new GET request to the same URL. If there is a new request for the same page but that request has the old content, then you have a datastore consistency issue. If there was NOT a new request that yielded a response with the data for the page, then you have a redirect issue.
If it turns out that you have a datastore consistency issue, then what's happening is the data is being stored, but the next request for that data might still get the old data. To make sure that doesn't happen, you need what's called "strong consistency."
In a normal App Engine project, you get strong consistency by putting entities in the same entity-group and using ancestor queries. I'm not certain of what database/datastore you're using for Django and how the different database layers interact with App Engine's consistency, so this could be wrong, but if you can give your users the right key and then fetch them from that key directly (rather than getting all users and filtering them by key), you might get strong consistency.

Cross Site Scripting with Hidden Inputs

My company gave me the task of resolving all security issues with a particular application. The security tream reported a cross site scripting error. The error lies in the following input field:
<input type="hidden" name="eventId" value="${param.eventId}"/>
The report from security wasn't very detailed, but the say they can make a POST request to the page that has the above tag including the following malicious code:
eventId=%22%3e%3csCrIpT%3ealert(83676)%3c%2fsCrIpT%3e
And that when the page reloads, it will have the following:
<input type="hidden" name="eventId" value=""><sCrIpt>alert(83676)</sCrIpt></value>
I am trying to "be the hacker" and show the vulnerability. But I can't figure out how they manage to get that script in there. I am guessing they include it as a URL parameter in the GET request for the form, but when I try to do it myself I get a 403 error. Does anyone know how the vulnerability can be shown?
I know there is a number of XSS questions on the site, but none seem to hit this topic.
So, I am not sure why, but my original hunch was correct. The script can be put on as a URL parameter. For some reason though, this was not working with our staging site. Only with running the application locally. I am not sure why, but this works (only locally):
http://localhost:8080/myUrl/MyAction.do?eventId=%22%3e%3csCrIpT%3ealert(83676)%3c%2fsCrIpT%3e
Doing that, you see an alert box pop up. I am planning to fix it using JSTL functions.
<%# taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
...
<input type="hidden" name="eventId" value="${fn:escapeXml(param.eventId)}"/>
Install [TamperData][1] add-on in firefox browser which let you edit the data before submitting. Doesn't matter if it's in POST or GET.
By using this hidden fields can be edited.
What you want to do to fix the problem, is to HTMLAttributeEncode the value before putting it inside the value-attribute. See OWASP ESAPI or MS AntiXSS for methods for doing HTML attribute encoding.
Seeing how the attack string is URL encoding, I think you guess about including it as a GET parameter seems reasonable.
I used the OWASP ESAPI API as the legacy jsp's didn't have JSTL available. This is what I used:
<input type="hidden" name="dataValue" value="<%=ESAPI.encoder().encodeForHTMLAttribute(dataValue)%>">
You can also use the API to filter request.Parameter() which I also needed, as in:
String userURL = request.getParameter( "userURL" )
boolean isValidURL = ESAPI.validator().isValidInput("URLContext", userURL, "URL", 255, false);
if (isValidURL) {
link
}
and:
String name = (String) request.getParameter("name");
name = ESAPI.validator().getValidInput("name ", name , "SafeString", 35, true);

Retrieving POST data from jQuery in Django without a form

I am currently able to use the post method of jQuery to a view pointed by myurl
jQuery.post("/myurl", {'value1':value1, 'value2':value2,
'csrftoken': '{{ csrf_token }}'},
function(data) {
alert("Data Loaded: " + data);
});
However, I don't know how to retrieve the posted data inside the view without using a form:
def save_user_graph(request):
if request.method == 'POST':
return HttpResponse(request.POST.get('value1'),status=201)
returns None.
If save_user_graph is returning None, then request.method is not POST. If save_user_graph is returning an HttpResponse with the word 'None' in it, then value1 isn't being sent correctly. Can you clarify which is the case?
If you have chrome, try navigating to the page with the developer toolbar open. You can go to the 'console' tab and view the AJAX request and see what data was sent with it, to make sure that the data was sent correctly.
Similarly, if you have firefox and firebug, you can go to the page and watch the ajax request and check the post parameters.
Assuming that the javascript works, you'll want to log request.POST in save_user_graph. In a pinch, you can just print request.POST and, assuming you're using the django dev server, the output will be printed in the dev server output.
We'll need a bit more debugging info before we can give a better answer. :)

jquery-autocomplete does not work with my django app

I have a problem with the jquery-autocomplete pluging and my django script. I want an easy to use autocomplete plugin. And for what I see this (http://code.google.com/p/jquery-autocomplete/) one seems very usefull and easy. For the django part I use this (http://code.google.com/p/django-ajax-selects/) I modified it a little, because the out put looked a little bit weired to me. It had 2 '\n' for each new line, and there was no Content-Length Header in the response. First I thought this could be the problem, because all the online examples I found had them. But that was not the problem.
I have a very small test.html with the following body:
<body>
<form action="" method="post">
<p><label for="id_tag_list">Tag list:</label>
<input id="id_tag_list" name="tag_list" maxlength="200" type="text" /> </p>
<input type="submit" value="Submit" />
</form>
</body>
And this is the JQuery call to add autocomplete to the input.
function formatItem_tag_list(row) {
return row[2]
}
function formatResult_tag_list(row) {
return row[1]
}
$(document).ready(function(){
$("input[id='id_tag_list']").autocomplete({
url:'http://gladis.org/ajax/tag',
formatItem: formatItem_tag_list,
formatResult: formatResult_tag_list,
dataType:'text'
});
});
When I'm typing something inside the Textfield Firefox (firebug) and Chromium-browser indicates that ther is an ajax call but with no response. If I just copy the line into my browser, I can see the the response. (this issue is solved, it was a safety feature from ajax not to get data from another domain)
For example when I am typing Bi in the textfield, the url "http://gladis.org/ajax/tag?q=Bi&max... is generated. When you enter this in your browser you get this response:
4|Bier|Bier
43|Kolumbien|Kolumbien
33|Namibia|Namibia
Now my ajax call get the correct response, but there is still no list showing up with all the possible entries. I tried also to format the output, but this doesn't work either. I set brakepoints to the function and realized that they won't be called at all.
Here is a link to my minimum HTML file http://gladis.org/media/input.html
Has anybody an idea what i did wrong. I also uploaded all the files as a small zip at http://gladis.org/media/example.zip.
Thank you for your help!
[Edit]
here is the urls conf:
(r'^ajax/(?P<channel>[a-z]+)$', 'ajax_select.views.ajax_lookup'),
and the ajax lookup channel configuration
AJAX_LOOKUP_CHANNELS = {
# the simplest case, pass a DICT with the model and field to search against :
'tag' : dict(model='htags.Tag', search_field='text'),
}
and the view:
def ajax_lookup(request,channel):
""" this view supplies results for both foreign keys and many to many fields """
# it should come in as GET unless global $.ajaxSetup({type:"POST"}) has been set
# in which case we'll support POST
if request.method == "GET":
# we could also insist on an ajax request
if 'q' not in request.GET:
return HttpResponse('')
query = request.GET['q']
else:
if 'q' not in request.POST:
return HttpResponse('') # suspicious
query = request.POST['q']
lookup_channel = get_lookup(channel)
if query:
instances = lookup_channel.get_query(query,request)
else:
instances = []
results = []
for item in instances:
results.append(u"%s|%s|%s" % (item.pk,lookup_channel.format_item(item),lookup_channel.format_result(item)))
ret_string = "\n".join(results)
resp = HttpResponse(ret_string,mimetype="text/html")
resp['Content-Length'] = len(ret_string)
return resp
You probably need a trailing slash at the end of the URL.
Also, your jQuery selector is wrong. You don't need quotes within the square brackets. However, that selector is better written like this anyway:
$("input#id_tag_list")
or just
$("#id_tag_list")
Separate answer because I've just thought of another possibility: is your static page being served from the same domain as the Ajax call (gladis.org)? If not, the same-domain policy will prevent Ajax from being loaded.
As an aside, assuming your document.ready is in your Django template, it would be a good idea to utilize the {% url %} tag rather than hardcoding your URL.
$(document).ready(function(){
$("input[id='id_tag_list']").autocomplete({
url:'{% url my_tag_lookup %}',
dataType:'text'
});
});
This way the JS snippet will be rendered with the computed URL and your code will remain portable.
I found a solution, but well I still don't know why the first approach didn't worked out. I just switched to a different library. I choose http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/. This one is actually promoted by jQuery and it works ;)