I consider myself newbie when it comes to securing my web applications.
I have built a website which updates the webpages regularly through an AJAX call. The Ajax call returns a decent JSON object to be used at the client side.
There is a simple problem I need to overcome: How can I prevent other people to use the same AJAX call without permission? What if they build a website, AND at the client side they allow their users to make the same AJAX call to my servers and grab what they need.. AND THEN parse it to their own needs at the client side?
I cannot put an extra layer of security like user authentication.
They won't be able to actually do this from the client directly because the browser will prevent cross domain AJAX requests for anything other than JSONP (scripts). That said, they can proxy it on their server if they want so it doesn't buy you much.
ASP.NET MVC has an antiforgery token mechanism that you should look at for inspiration. The basic idea is that you use both an encrypted cookie and an encrypted, hidden form input containing the same data that you write to each page that you want to secure. Do your AJAX calls using a POST and make sure to send back the form input. On the server-side decrypt the cookie and input and compare the data to ensure they're the same. Since the cookie is tied to your domain, it will be much harder to inject in the request that is being sent back. Use SSL and regenerate the cookie/input content periodically to make it even harder to fake the cookie/input.
You can check the HTTP_REFERER http header and see if the request originates from your page. This can however be spoofed, so don't think of it as a bulletproof solution. The best counter-meassure is user authentication, really.
You can't. That's because you can't differenciate between an AJAX call from your web app and another user's webapp.
Here are some things that might help a little bit.
Obscuring/encrypting your AJAX response. This fails mainly because you have to include the decryption code in your app as well.
Check the IP origin. If the IP didn't access your server before, you can assume that the AJAX call is not from your website. This doesn't work if a) the user switches the IP while being on your site / timing out or b) if another website sends a fake http request first before using your AJAX API.
Another idea would be to send Javascript instead of a JSON object. The Javascript should contain all the logic needed to update your website, and of course could check if the website is your own. (window.location). That has some disadvantages though: more work for you, higher traffic load and it can be broken anyways.
I don't think it's a bad thing actually. Another website could have just as easily scraped the info from your website.
If by "stealing" you mean getting some content from your website (using HTTP GET), that's more or less the same problem as hot-linking. You could have some basic protection technique using the HTTP Referer header (it can be worked around, but it works in most cases).
The other problem you have (making sure the requests come from your application) have to do with CSRF (Cross-Site Request Forgery). There are various protection mechanisms against this, mostly based on embedding tokens in forms for example.
You could potentially combine the two approaches, although the real protection against getting the content would come from user authentication (otherwise, the other site could also get the page from which you're delivering those tokens and proxy it).
(In addition, techniques that rely on remembering the IP address would probably not work well in the whole web architecture: it might cause problems if you get a pool of proxy servers or if the client is a mobile device that may change IP address between various requests, which would be perfectly legitimate.)
Related
Let me explain in detail
I've 2 servers hosted and one of them for Back-end and other is for Front-end.
Back-end server : 127.0.0.1:8000 (just for explaining)
Front-end server : 127.1.1.1:9000
User requests UI from Front-end server and if he wants to create an account on my website he needs to send POST request to 127.0.0.1:8000/create-account/ and this works fine
but if I open console of other website or make use of Postman, I'm able to achieve the same results.
So I want to prevent this thing and only allow anyone to create account from my website only.
Methods which I've tried
I've used windows.location() and sent it to server and then verify if domain name matches. But in this method everyone can just pass it simply via fetch()
I've used allow only IP address, But if I push my website in production Other visitors get 403 error.
I develop back-end with help of Django and rustlang
It isn't possible. You can make it hard for entry-level programmers to reverse-engineer your solution, but there isn't any way to prevent access to your API if you are going to allow access to it from some public UI.
IP address-based restriction will not work here because your backend will receive the IP of the user. In this case, you will be blocking access to users, not to any UI. Even the host header verification doesn't work here as anyone can use a proxy server, i.e. NGINX, to override the headers and can fake the request to originate from an intended website.
IP address-based authorization can work only if API calls originate from a server and your API server receives the same IP address for each API call. But for your use case, it isn't applicable.
The older techniques like CSRF are useless too as anyone can easily retrieve the token and can send it. In short, if you make something public, it can be reverse-engineered. If you are accepting public registrations, there shouldn't be anything to worry about the registration source. You should think about solutions like email verification etc. to reduce the spam if that's the concern.
You could have your frontend solve a recaptcha and send the solution to the backend. Verify the solution before accepting the request. It is still possible to bypass although a bit harder.
My web application's authentication mechanism currently is quite simple.
When a user logs in, the website sends back a session cookie which is stored (using localStorage) on the user's browser.
However, this cookie can too easily be stolen and used to replay the session from another machine. I notice that other sites, like Gmail for example, have much stronger mechanisms in place to ensure that just copying a cookie won't allow you access to that session.
What are these mechanisms and are there ways for small companies or single developers to use them as well?
We ran into a similar issue. How do you store client-side data securely?
We ended up going with HttpOnly cookie that contains a UUID and an additional copy of that UUID (stored in localStorage). Every request, the user has to send both the UUID and the cookie back to the server, and the server will verify that the UUID match. I think this is how OWASP's double submit cookie works.
Essentially, the attacker needs to access the cookie and localStorage.
Here are a few ideas:
Always use https - and https only cookies.
Save the cookie in a storage system (nosql/cache system/db) and set it a TTL(expiry).
Never save the cookie as received into the storage but add salt and hash it before you save or check it just like you would with a password.
Always clean up expired sessions from the store.
Save issuing IP and IP2Location area. So you can check if the IP changes.
Exclusive session, one user one session.
Session collision detected (another ip) kick user and for next login request 2 way authentication, for instance send an SMS to a registered phone number so he can enter it in the login.
Under no circumstances load untrusted libraries. Better yet host all the libraries you use on your own server/cdn.
Check to not have injection vulnerabilities. Things like profiles or generally things that post back to the user what he entered in one way or another must be heavily sanitized, as they are a prime vector of compromise. Same goes for data sent to the server via anything: cookies,get,post,headers everything you may or may not use from the client must be sanitized.
Should I mention SQLInjections?
Double session either using a url session or storing an encrypted session id in the local store are nice and all but they ultimately are useless as both are accessible for a malicious code that is already included in your site like say a library loaded from a domain that that has been highjacked in one way or another(dns poison, complomised server, proxies, interceptors etc...). The effort is valiant but ultimately futile.
There are a few other options that further increase the difficulty of fetching and effectively using a session. For instance You could reissue session id's very frequently say reissue a session id if it is older then 1 minute even if you keep the user logged in he gets a new session id so a possible attacker has just 1 minute to do something with a highjacked session id.
Even if you apply all of these there is no guarantee that your session won't be highjacked one way or the other, you just make it incredibly hard to do so to the point of being impractical, but make no mistake making it 100% secure will be impossible.
There are loads of other security features you need to consider at server level like execution isolation, data isolation etc. This is a very large discussion. Security is not something you apply to a system it must be how the system is built from ground up!
Make sure you're absolutely not vulnerable to XSS attacks. Everything below is useless if you are!
Apparently, you mix two things: LocalStorage and Cookies.
They are absolutely two different storage mechanisms:
Cookies are a string of data, that is sent with every single request sent to your server. Cookies are sent as HTTP headers and can be read using JavaScript if HttpOnly is not set.
LocalStorage, on the other hand, is a key/value storage mechanism that is offered by the browser. The data is stored there, locally on the browser, and it's not sent anywhere. The only way to access this is using JavaScript.
Now I will assume you use a token (maybe JWT?) to authenticate users.
If you store your token in LocalStorage, then just make sure when you send it along to your server, send it as an HTTP header, and you'll be all done, you won't be vulnerable to anything virtually. This kind of storage/authentication technique is very good for Single-page applications (VueJS, ReactJS, etc.)
However, if you use cookies to store the token, then there comes the problem: while token can not be stolen by other websites, it can be used by them. This is called Cross-Site Request Forgery. (CSRF)
This kind of an attack basically works by adding something like:
<img src="https://yourdomain.com/account/delete">
When your browser loads their page, it'll attempt to load the image, and it'll send the authentication cookie along, too, and eventually, it'll delete the user's account.
Now there is an awesome CSRF prevention cheat sheet that lists possible ways to get around that kind of attacks.
One really good way is to use Synchronizer token method. It basically works by generating a token server-side, and then adding it as a hidden field to a form you're trying to secure. Then when the form is submitted, you simply verify that token before applying changes. This technique works well for websites that use templating engines with simple forms. (not AJAX)
The HttpOnly flag adds more security to cookies, too.
You can use 2 Step Authentication via phone number or email. Steam is also a good example. Every time you log in from a new computer, either you'll have to mark it as a "Safe Computer" or verify using Phone Number/Email.
"Instead of using cookies for authorization, server operators might
wish to consider entangling designation and authorization by treating
URLs as capabilities. Instead of storing secrets in cookies, this
approach stores secrets in URLs, requiring the remote entity to
supply the secret itself. Although this approach is not a panacea,
judicious application of these principles can lead to more robust
security." A. Barth
https://www.rfc-editor.org/rfc/rfc6265
What is meant by storing secrets in URLs? How would this be done in practice?
One technique that I believe fits this description is requiring clients to request URLs that are signed with HMAC. Amazon Web Services offers this technique for some operations, and I have seen it implemented in internal APIs of web companies as well. It would be possible to sign URLs server side with this or a similar technique and deliver them securely to the client (over HTTPS) embedded in HTML or in responses to XMLHttpRequests against an API.
As an alternative to session cookies, I'm not sure what advantage such a technique would offer. However, in some situations, it is convenient or often the best way to solve a problem. For example, I've used similar techniques when:
Cross Domain
You need to give the browser access to a URL that is on another domain, so cookies are not useful, and you have the capability to sign a URL server side to give access, either on a redirect or with a long enough expiration that the browser has time to load the URL.
Examples: Downloading files from S3. Progressive playback of video from CloudFront.
Closed Source Limitations
You can't control what the browser or other client is sending, aside from the URL, because you are working with a closed source plugin of some kind and can't change its behavior. Again you sign the URL server side so that all the client has to do is GET the URL.
Examples: Loading video captioning and/or sprite files via WEBVTT, into a closed-source Flash video player. Sending a payload along with a federated single sign-on callback URL, when you need to ensure that the payload can't be changed in transit.
Credential-less Task Worker
You are sending a URL to something other than a browser, and that something needs to access the resource at that URL, and on top of that you don't want to give it actual credentials.
Example: You are running a queue consumer or task-based worker daemon or maybe an AWS Lambda function, which needs to download a file, process it, and send an email. Simply pre-sign all the URLs it will use, with a reasonable expiration, so that it can perform all the requests it needs to without any additional credentials.
I have a RESTful API which has annotations like #Consumes(MediaType.JSON) - in that case, would the CSRF attack still be possible on such a service? I've been tinkering with securing my services with CSRFGuard on server side or having a double submit from client side. However when I tried to POST requests using FORM with enctype="text/plain", it didn't work. The technique is explained here This works if I have MediaType.APPLICATION_FORM_URLENCODED in my consumes annotation. The content negotiation is useful when I'm using POST/PUT/DELETE verbs but GET is still accessible which might need looking into.
Any suggestions or inputs would be great, also please let me know if you need more info.
Cheers
JAX-RS is designed to create REST API which is supposed to be stateless.
The Cross Site Request Forgery is NOT a problem with stateless applications.
The way Cross Site Request Forgery works is someone may trick you to click on a link or open a link in your browser which will direct you to a site in which you are logged in, for example some online forum. Since you are already logged in on that forum the attacker can construct a url, say something like this: someforum.com/deletethread?id=23454
That forum program, being badly designed will recognize you based on the session cookie and will confirm that you have the capability to delete the thread and will in fact delete that thread.
All because the program authenticated you based on the session cookie (on even based on "remember me" cookie)
With RESTful API there is no cookie, no state is maintaned between requests, so there is no need to protect against session hijacking.
The way you usually authenticate with RESTFul api is be sending some additional headers. If someone tricks you into clicking on a url that points to restful API the browser is not going to send that extra headers, so there is no risk.
In short - if REST API is designed the way it supposed to be - stateless, then there is no risk of cross site forgery and no need to CSRF protection.
Adding another answer as Dmitri’s answer mixes serverside state and cookies.
An application is not stateless if your server stores user information in the memory over multiple requests. This decreases horizontal scalability as you need to find the "correct" server for every request.
Cookies are just a special kind of HTTP header. They are often used to identify a users session but not every cookie means server side state. The server could also use the information from the cookie without starting a session. On the other hand using other HTTP headers does not necessarily mean that your application is automatically stateless. If you store user data in your server’s memory it’s not.
The difference between cookies and other headers is the way they are handled by the browser. Most important for us is that the browser will resend them on every subsequent request. This is problematic if someone tricks a user to make a request he doesn’t want to make.
Is this a problem for an API which consumes JSON? Yes, in two cases:
The attacker makes the user submit a form with enctype=text/plain: Url encoded content is not a problem because the result can’t be valid JSON. text/plain is a problem if your server interprets the content not as plain text but as JSON. If your resource is annotated with #Consumes(MediaType.JSON) you should not have a problem because it won’t accept text/plain and should return a status 415. (Note that JSON may become a valid enctype one day and this won’t be valid any more).
The attacker makes the user submit an AJAX request: The Same Origin Policy prevents AJAX requests to other domains so you are safe as long as you don’t disable this protection by using CORS-headers like e.g. Access-Control-Allow-Origin: *.
I am working on creating a toolbar application that will invoke a URL on the server and increase a User's points(as an incentive to use the toolbar). Right now the URL is a GET(I can and will change it to POST).
The issue is, I need to make sure that someone cannot, using any sort of a hack, increase the points. The URL is ofcourse a publicly accessible URL.
Will Basic HTTP Authentication make sense in this case? If yes, wont I need to store username-password with the toolbar, which again can be easily hacked?
-thanks
if I'm not mistaking Basic HTTP Authentication send the password in clear text over the network
I suggest you to use Digest HTTP Authentication + TLS/SSL