In our recent applications we are using lots of AJAX in JS files to avoid frequent postbacks. But I'm worried about the public getting into some of our business logic by just checking the JS file. They can also alter the data being sent to the server using firebug or such features. So how can we avoid this scenario and protect our code from being easily visible to the world.
In this case, the public can see the server side function, parameters etc easily. So how can we avoid this headache to some extent.
var param = { id: id };
var param = JSON.stringify(param);
$.ajax({
type: "POST",
url: "qmaker.aspx/deleteQuestion",
data: param,
contentType: "application/json; charset=utf-8",
dataType: "json",
global: false,
beforeSend: function () {
$.blockUI({
message: '<h3>Deleting Question..<br><small>Please wait for a moment...</small></h3>'
});
},
success: function (data) {
if (data.d == 1) {
var n = noty( type: 'success', text: 'Question Deleted successfully.', /* ... */)
var oTable = $('#table_question).DataTable();
var row = oTable.row($(that).parents('tr:first'));
/* ... */
You don't get to pick what the client sends you. I can submit forms without even reading your HTML.
You also don't get to pick what, out of what you send to the client, the client may or may not read. You sent me a JS file, it's out of your hands now.
In traditional programs, you'd be able to relatively safely sell programs by compiling them, because the original source code was unrecoverableto some definitions of unrecoverable.
With JavaScript, you send your code to the browser, and ask them nicely to execute it. You can't expect the browser not to read all of the code, right? So why can you expect the same of the user, who is using the browser to view your page?
Make sure you application is secure and airtight even if details about your business logic are leaked. A good security stands strong even if everything about the system is known to an attacker, including the source code and the database structure.
Then again
You don't need to expose the inner workings of the server to JavaScript. The "code" you posed doesn't really reveal anything in terms of how the server works, all I know is that there's a page on qmaker.aspx that supports the deleteQuestion path, and when I hit that, with an ID, that question will be deleted. It's now up to you to think what an attacker might do with this information, and seal any attack vectors.
If you want to make it safe you should implement authentication and tokenized requests. This way it doesn't matter if the public see the requests, they will not be able to make successful requests without being authenticated and having a valid token.
Edit below: to provide some extra information.
Surely in your applications you implement some kind of login so users are authenticated and allowed (or forbidden) to use certain parts of your application.
When a user logs in, you could generate a (temporary) token on the server side, store it and pass it back to the user through browser session or similar. Then pass the token as a parameter to the ajax calls.
$ajax(url, {
data: {
token: session.token,
action: 'delete',
id: entryID
}
}
The server will check if the token has been passed and it's valid against the db records. If it is it will just perform the requested operation and return a reply, or it could just return a 401 (unauthorized) error..
If you want something more advanced and perhaps safer, you could search for oauth 2.0 authentication.
Related
I'm wondering what the standard solution is to ajax failing due to (OIDC) SSO redirect/refresh. It's insidious because the failure is silent, the web page appears to be working properly.
I have a simple web page with static HTML and simple javascript that populates the page via ajax and refreshes it periodically.
The webpage and JS are both access-controlled via the same OIDC SSO. This works, but can fail in the following ways when the ajax call is rejected 401 due to needing an authentication refresh. (This is not full password authentication, this is just "check that my token is ok, and see that it is, and keep going as if nothing had happened".)
Back end and front end are both served from the same server by a basic Apache service with the same Access Control and Authorization requirements.
If a user navigates to the page in such a way that a cached version of the HTML is loaded and just the ajax runs. (e.g. back button)
If the page is left sitting for long enough, I believe it refreshes will also fail for the same reason.
I have worked around the issue as shown below, but it feels like a hack, like there must be some much more standard way to do this.
// This function is called every 30s on a timer
function updateData(args, callback) {
$.ajax({
xhrFields: { withCredentials: true },
url: "/getit?" + args,
success: function(data) {
localStorage.removeItem('pagereloaded')
callback(data);
},
statusCode: {
// Reload is because SSO tokens can timeout causing ajax to fail.
// In these cases we want to reload the page right away.
// But what if it's just a genuine auth failure, we do not want to go into an infinite reload loop.
// So pagereloaded and timer try to reload quickly a first time, but then avoid a loop after that.
401: function () {
if (localStorage.getItem('pagereloaded') == null || (Date.now() - start_time) > 60000) {
localStorage.setItem("pagereloaded", 1)
location.reload();
}
}
}
});
}
WEB AND API MODULES
Sounds like the Apache module you are using is intended only for website requests, and is not intended for direct API requests. The more standard way to deal with this is via separate modules that are tailored to their clients - something like this:
PATH: https://example.com/www/** --> uses an OIDC module to verify credentials during web requests
PATH: https://example.com/api/** --> uses an OAuth module to verify credentials during API requests
If you search around you will see that there are a number of Apache modules available, some of which deal with security for web requests and some of which deal with security for API requests.
BEHAVIOUR
An API module should enable its clients to distinguish missing, invalid or expired API credential errors (usually classified as 401s) from other types of error. In normal usage, 401s should only occur in applications when access or refresh tokens expire, or, in some cases, when cookie encryption or token signing keys are renewed. These error cases are not permanent and re-authenticating the user will fix them.
Other types of error should return a different status code to the client, such as 400 or 500, and the client should display an error. As an example, if a client secret is misconfigured, it is a permanent error, and re-authenticating the user will not fix the problem. Instead it would result in a redirect loop. By testing these error conditions you will be satisfied that the behaviour is correct.
UPDATED CODE
You can then write simple code, perhaps as follows. The client side code should be in full control over behaviour after a 401. Whether you reload the page or just stop making background requests is up to you to decide.
function updateData(args, callback) {
$.ajax({
url: "/api/getit?" + args,
success: function(data) {
callback(data);
},
statusCode: {
401: function () {
location.reload();
}
}
});
}
Note also that the withCredentials flag is only needed for cross origin requests, such as those https://www.example.com to https://api.example.com, so I have omitted it from the above code, since it sounds like you have a same domain setup.
Users of my web application are expected to provide bug reports as a GitHub issue, with a pregenerated title and body.
This works perfectly fine using GET for small bodies:
const title = getLastErrorTitle();
const body = getAllTheLogMessages();
window.open(`https://github.com/theuser/therepo/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}`);
If the user is logged in, GitHub presents the user with a new issue with the title and body already filled out, perfect. If not, GitHub prompts the user to log in and it works the next time.
However, if the body is too large, the GET request fails because the URL becomes too long.
After consulting the manual I tried doing the same with POST but I get a 404 from GitHub with the following test request (jQuery for brevity):
$.ajax({
type: "POST",
url: "https://api.github.com/repos/theuser/therepo/issues",
data: data = {title: "Test", body: "Test Body"},
});
My suspicion is, that the GitHub API was not designed with my use case in mind, but that POST always requires authentication and creates the full issue in one go, without letting the user change it beforehand like it is possible with GET.
How can I transfer the functionality of the GET method over to the POST method? I just want GitHub to present the user, that is currently logged in inside the browser, with a prefilled issue, without needing a token.
You can't. Otherwise, it would be a major CSRF exploit.
However, you can use OAuth authentication that will allow your application to use some features : https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/
Or simply, redirect the user to a new issue page (for exemple with a simple HTML link <a>) with some automatic content, using this pattern :
https://github.com/{theUser}/{theRepo}/issues/new?body={theContentYouWhant}&title={theTitleYouWhant}
Example : https://github.com/CristalTeam/php-api-wrapper/issues/new?body=Hi,%20this%20is%20the%20body%20you%20want&title=Hello,%20this%20is%20a%20prefill%20issue
What I would suggest here is to generate a personal_auth_token at gihub and pass this token in the headers under Authorization field.
To generate personal_auth_token, login to github.com, go to settings -> developers settings -> Personal access tokens and generate one.
Pass this token in headers under Auhtorization: token. So in your AJAX request, it could look something like this:
$.ajax({
url: *yourUrl*
...
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', *token*));
},
});
One thing to note here is each of the developers POSTing to the repo will be requiring to generate their access token and you can't push this token on to a public Github repository because of obvious security breach. If you accidentally do so, the token is revoked immediately and you'll be required to create a new one.
I want to restrict AJAX calls other than my application. I don't want my AJAX request to send response when called from outside my application, even when the url of AJAX call is copied and pasted in browser. I am using node, express and mongodb.
What I did was add some headers in my ajax calls:
// javascript
$.ajax({
type: 'POST',
dataType: 'json',
headers: {"Content-Type": "application/json", "app-ver": 1.5}
})
.
// php
$client_ver = floatval($_SERVER['HTTP_APP_VER']);
// I also check $_SERVER['CONTENT_TYPE'] to be: 'application/json'
// and post method. (ask me I'll add)
if ( $client_ver != 1.5 )
{
echo '{}';
exit();
}
Edit:
Another way would be creating a "session" with your app, meaning every request after a successful login has to carry a token (at least)
and have your app attach lots of unique header key-values that is only recognizable by your server, and not any two requests are a like (eg: include time in header, and hash it with REST command, and have server check it to make sure it's a unique command, and it's not just being manipulated.
* You have to know your session creation algorithm and it HAS to be unique, or if you don't know how to do it, I suggest research more about it.
If your application runs on a user's machine (like a JavaScript web app) then it is impossible to prevent someone from making the calls from outside of your app. You can make it harder by using a nonce with each request, but even then someone could build their own app that mimics your app and makes the calls in the correct order.
In short: you can't ever fully trust the client and you can't prevent someone from spoofing the client. You need to re-examine your requirements.
I'm trying to make an app using phonegap, but what I want to know is if it is possible to store information online. For example, say there is a number variable, and it is added to when a button is pushed. Could that value be saved somewhere and then a totally different device can retrieve the variable?
I looked at databases, but I couldn't really understand it. I want something that can be accessed by any device as long as It has a key or something.
Is this possible? If so, how would I do it?
PhoneGap uses JS so you cannot connect to the database directly. You should create a Web service using server side languages like PHP on external server and make ajax request on your web service. This approach is possible using PhoneGap.
Sample Code will look somewhere near:
function FetchData() {
$.ajax({
async: false,
type: "GET",
url: "Your_WebService_URL",
dataType: "json",
success: function(data) {
$.each(data, function(i, object) {
if(i==="title"){
document.getElementById("title").InnerHTML = object;
}
if(i==="home_image"){
document.getElementById("title").InnerHTML = '<img src="'+object+'"/>';
}
});
},
error: function() {
alert("There was an error loading the feed");
}
});
The web service, in this case json will throw the variables. May me somewhere like this :
[{"title":"my application"},{"home_image":"http://link.com/image.png"}]
I think this article is useful to you: Loading external data into a PhoneGap app using the jQuery JSONP plugin for cross-domain access. Also see this similar question here:
This is entirely possible.
You essentially need two components: the client interface, and the server.
The client displays the results to the users, and, using your example, waits for a button to be pushed. On the push of that button, the client would send a request to the server to increment the stored value (possibly through a jQuery.post, or get, function call).
The server page, written in php for example, receives this request, and accesses a file, or more realistically a database, to increment the value.
With some Googling, this should be very doable, but post specific questions if you get stuck.
I am writing a simple widget that renders a canvas participation graph just like the one's on github.
It uses the data at http://github.com/[user]/[repo]/graphs/participation
The widget works great and is basically done. The only problem I have is when I try to retrieve the json data from the above link via XHR (rather than just copying and pasting into the widget as I have been), I run into the same origin access control problem.
Is there any way I can access this information at all, either via XHR or some hidden github api feature?
I believe Github supports JSONP and CORS through its API. You could also setup a server-side proxy, through which XHR requests are made to a same-origin page which then does a server-side request to Github.
To answer your question about the proxy, yes it's very simple. I had actually done this exact thing about two years ago using Python and Tornado. I realize this isn't PHP, but it reads close enough to english to give you the idea about how it works. This particular proxy was returning a raw gist.
# /proxy/gist
class GetGistHandler(BaseHandler):
def get(self, id, filename):
url = 'http://gist.github.com/raw/%s/%s' % (id, urllib.quote(filename))
resp = urlfetch.fetch(url)
self.finish(resp.content)
It can then be consumed with something along the lines of
$.ajax({
url: '/proxy/gist',
dataType: 'JSON',
data: {
id: $('#id').val(),
filename: $('#filename').val()
},
success: function(json) {
// ...
}
});