I have an ASP.NET website that heavily uses JSON services. The basic structure is: jQuery Plugins -> JSON Service -> Server-Side BAL.
But, this solution is obviously not secure, since a malicious user can run a tool such as Fiddler and capture JSON calls on their machine, then replay these JSON calls changing parameters, etc.
If I were to put the web services folder under SSL, what protections would it give me? I tried putting the entire site under SSL, but still running Fiddler I can see clear-text messages going to HTTPS protocol, and I can replay those messages from Fiddler with the same or changed parameters.
I obviously have little knowledge about SSL and need some help. Does it sound like my SSL is not setup correctly, or being able to see SSL traffic via Fiddler is expected? If the latter, what protection does SSL provide in my scenario?
Thank you.
SSL only encrypts the transport. Meaning a third party cannot eavesdrop on the data exchange between the client and your server. It does not add any security features to the server or service itself.
What you need is a proper authentication, permission and validation system. Every request needs to be checked for its validity. Be prepared to receive any sort of request with any sort of parameters, be that because the user fiddled with the parameters, because of a bug in your code or whatever. If a request is invalid, meaning if a particular user is not allowed to do a certain thing, reject the request.
This is not some addon technology you can implement, it's a core design consideration of your service.
If Bob implements SSL on his website, then when Alice uses the site, then Mallory will not be able to intercept the data or alter it in-flight. SSL keeps messages between Alice's browser and Bob's server secret. It does not keep messages between Alice and Alice's browser secret.
There are two approaches you can take to protect yourself from malicious data.
Escape (or the equivalent) everything before inserting it into a different format. e.g. use prepared statements on SQL, build JSON with a JSON serializer and not string mashing, etc.
Authenticate users and only accept data from those that you trust
Related
I am prototyping a simple web app front end that needs to fetch JSON data from my server. The server itself works fine -- I can click on the link, and the JSON data shows up in the browser. But the following simple script fails:
fetch('https://x.x.x.x:8000') // MY URL FAILS
// fetch('https://jsonplaceholder.typicode.com/todos/1') // ALTERNATE URL WORKS
.then(function() {
alert("Successful")
})
.catch(function() {
alert("Failure")
});
I'm completely new to this sort of front-end work (and to Javascript in general), so I might be overlooking an obvious reason, but the two that come to mind are
my server uses a self-signed certificate for testing purpose; and/or
I'm using a non-standard port.
The first of these possible explanations seems more likely.
Accessing the web page generates a bunch of errors, none of which mean anything to me (except for not finding the favicon):
I will temporarily post the full URL in a comment below, in case anyone else wants to see what happens, but I would delete it once a working solution is suggested.
To answer your question as asked, no, you definitely can't use fetch to force the client (browser) to ignore cert errors. Especially in cross-origin requests (and going from one port to another is cross-origin), that would be a HUGE security hole. It would allow anybody who could get a man-in-the-middle position on a victim's network (not hard) to steal information from the victim's HTTPS connections using fraudulent certificates to intercept the HTTPS requests and responses.
You might be able to force server-side JS (in Node or similar) to ignore cert validation errors, since in that case you (hopefully!) control the code the server is running. But it doesn't look like that's what you're doing, and in a web page, somebody else (the server owner) controls what code you (the browser) are running, so you definitely can't let that code turn off important security features!
Attack scenario for if JS could turn off cert validation:
Suppose you and I both control web servers. I, a malicious attacker, would like to intercept the traffic between your users and your web server. I even have a man-in-the-middle (MitM) network position on some of your users! However, you are of course using TLS (via HTTPS), so I can't decrypt or modify the traffic.
However, your users sometimes connect to my server as well, not knowing it is malicious (maybe I mostly use it to serve relatively innocuous stuff, like a comment system or analytics tools, so lots of sites embed my scripts). My server can tell when a browser requests content from an IP address where I could launch an MitM attack, and serve them malicious scripts.
Now, in the real world, this doesn't matter! Sites don't trust other sites, because of the Same-Origin Policy, a critical browser security feature. My site (or the scripts I serve) can cause your users to submit requests to any other server that I choose, but they can't read the responses (if the other server is cross-origin), and they can't turn off certificate validation so my MitM position is mostly useless.
However, suppose that there was a way - as you propose - for scripts to tell the browser "it's ok, just trust this one particular self-signed cert when making this request". This changes everything. My MitM host will generate a self-signed cert (and corresponding private key) for your site, and send the cert to my own web server. When a potential victim loads a script from me, it only only contains instructions to make HTTP requests to your site, it also specifies that the browser should trust the self-signed certificate that my MitM node generated.
The victim's browser would then start the request, attempting to establish a TLS connection to your server. My MitM node would intercept the request, and reply with its self-signed certificate. Normally the browser would reject that, but in this case it doesn't because you created a way to tell browsers to accept a particular self-signed cert. Therefore, the victim's browser trusts my self-signed certificate. The actual request never even makes it to your server. The victim's browser, believing itself to be interacting with the legitimate server (yours) rather than with my MitM host, sends an HTTP request containing secrets such as cookies and/or API keys / bearer tokens / login credentials / etc. My MitM intercepts that (as it's intercepting all traffic), decrypts it (because it is in fact one end of the TLS tunnel, this is trivial), and can access the victim's account on your server. (My MitM host can also duplicate the responses from your server that the victim would usually see, to keep them unsuspecting. The MitM host can even tamper with this responses, if I want it to mislead the user.)
The usual way to solve this is to install the server's certificate as trusted in the browser (or in the OS). That way, the browser will recognize the certificate's issuer (itself) as valid, and consider the certificate valid.
What happens if you go to https://x.x.x.x:8000/ in the browser directly? If you get a certificate error, well, that's your problem: the browser doesn't trust the certificate of the server hosted on that port. You should have an opportunity to temporarily or permanently trust that certificate (exact details will depend on the browser).
Note that, of course, doing this on your own computer won't fix it for anybody else's computer. They'd need to manually trust your certificate too.
The actual solution is, of course, to install a trusted certificate. Perhaps you should try Let's Encrypt or similar, for a nice free cert that every client will trust without extra shenanigans?
Just had the same problem and stumbled upon the solution by accident. It is possible by just making the user open the self-signed site, click on 'Show more' and 'Accept the risk and continue'. After doing that, fetch requests go through like nothing ever went wrong.
It works on Firefox:
and Chrome:
This method just has the caveat that you have to do the setup, and on Chrome it displays 'Not secure' even when the rest of the page is secure.
But if you need HTTPS locally, this works like a charm. Hope this helps the people who came here from Google :)
EDIT:
Also worth mentioning, I tested it on localhost but it works everywhere.
I am submitting a form by using "POST" method. But, even I submit the form using "POST" method, I can see the submitted form data in http headers. Am using live http headers plugin to check the headers. I am trying to save secure info. If the browser has "live http headers" plugin, easily any one can trap the data. So, if I want to hide the submitted data in http headers also, what do I need to do?
If it is not possible to hide the submitted form data in http headers, which mechanism I could follow to encrypt the data at client side(so that even if data is visible in http headers, it would be in encrypted format. So, no one can understand) and decrypt and process the data at server side. I am totally blocked here.
Please help me out from this.
appreciate any help.
Thanks in advance.
There appears to be a bit of confusion regarding how an Http POST works. I'm assuming you are viewing the headers in either the client browser's debugger or on the server. In that case, the data being sent should be readable. The client side debugger actually displays the headers before they are encrypted and sent across the wire.
On the server, the post data should also be available in unencrypted format.
What is sent over the internet would be encrypted, provided that you are using https:// in your form action instead of http://
You can't really do that, I mean you could but anything on the front end can be easily reverse engineered. Your best bet for securing form data is to implement CSRF of which Jeff Atwood did a good post on here and the comments are quite good as well.
Aside from that; like one of the comments above says, you can use SSL to secure the data going to and from the server.
Comments weren't long enough for this
The steps towards getting secure, without knowing your technology stack would be to get an SSL certificate for the origin and destination of your post request, if you don't have control of the destination your journey ends here but head over to one of the hundreds of SSL certificate providers available, I usually use Start SSL because it's free and pretty good.
You'll need to give us some more info on your technology stack to go any further but assuming you're using PHP and Apache you'll need to do a few things on your server to get the certificate.
Firstly generate your Private Key using this command:
openssl genrsa -des3 -out www.yourdomainname.com.key 2048
It will ask you for a few details, fill them all out as best you can and write them down somewhere, specifically the password.
Once you have this, you need to generate a certificate signing request or a CSR for short, this is achieved by running the below command
openssl req -new -key www.yourdomainname.com.key -out www.yourdomainname.com.csr
The password you entered to create the private key, when it asks; enter it here.
You'll also be asked for a load of details, from my memory this is what it will ask and it's generic format
Country Name: GB
State or Province Name (in full): London
Locality Name (city): London
Organization Name: Your company name
Organizational Unit Name: Probably IT or development
Common Name: Enter your domain name here in FULL, without http://
When it asks for
Email Address
password challenge
optional company name
don't enter anything...
validate your CSR using
openssl req -noout -text -in www.mydomain.com.csr
You can now use this CSR to sign your request with Start SSL Once you have your crt from Start SSL open your server config (with apache its usually http-vhosts.conf in /etc/apache2/extra/ and create this block inside of it
<VirtualHost *:443>
DocumentRoot /var/www/www.yourdomainname.com
ServerName www.yourdomainname.com
SSLEngine on
SSLCertificateFile /path/to/your/www.yourdomainname.com.crt
SSLCertificateKeyFile /path/to/your/www.yourdomainname.com.key
SSLCertificateChainFile /path/to/StartSSL.crt
</VirtualHost>
Restart apache and you should be able to access your website using https
Hopefully I've got that all correct, I'll edit for any issues.
Well, there is no easy way but from other posts that I have found:
Take a look at this post. This does not hide the values in POST but using jquery serializes them. You can use your own conventions to make it look like a mess.
Take a look at this article. CLearly explains everything you should know about cross site request forgery.
Have a look at this link. They provide a toolkit to use encrypted forms, called Open Data Kit.
Are you using OpenSSL?
The simplest solution is to enable HTTPS support on your server, and serve the pages only via HTTPS, by turning off the standard HTTP connector.
You won't have to any special development, just switching to HTTPS will ensure that the data cannot be read in transit, and gives the assurance to the viewers of your pages that it's really your server that they are talking with, and not someone doing a man-in-the-middle attack.
The HTTPS technology transparently handles all the concerns that you are trying to handle manually. The browser will exchange with the server a temporary encryption key that is used to encrypt all data sent data back and forth.
The server contains a certificate signed by a certificate authority that is used to sign the data, to prove to browsers that it's really your server.
All of this is handled in a completely transparent and automated way, without any extra development. You just need to contact a certificate authority and get them to create you a certificate, see this tutorial.
You also need to enable HTTPS on the server, this is done via configuration and all servers support it.
A "header" is just another encapsulation. There is no difference between that and the abstract idea of "body". One is not inherently more or less safe for carrying data over wire, so your focus should not be on solving this issue. Also, post data technically is in the body.
If security is your objective here, then you will focus on preventing what someone could do if they had privilege in your client/server exchange. Then you would use SSL, http-only cookies (or well thought-out local storage) good session timeouts, and your usual smart coding practices. Generally we should assume most data is viewable in transit, and prioritize against making that privilege even worthwhile for an attacker
If you were really that truly concerned about MITM attacks against your form post data, I suppose you could throw together a little JS to encrypt and maybe even post over web-sockets, but that's akin to not really doing anything at all IMHO.
I'm currently planning to develop a HTML5 app. The basic concept is the following:
A user should be able to create a profile with username and password. The Server should be implemented in Ruby on Rails providing a JSONP Api (for Cross-Domain issues).
So the App will send Ajax requests to the Server and get responses from it.
My idea was now to transmit a session_key (generated by server) on the first response back to the client. Then the client has to authenticate himself with this token.
But now i have some issues.
How can i secure the first call of the client (when he is transmitting user and password)?
How can i protect the Session-key from beeing spyed out?
I am a complety noob in security aspects. Therefore it would be great if i could get some hints where to look at.
Secure your connection with SSL. This should require no changes in your code apart from putting 's' after 'http' ;-).
I used add a checksum to the ajax parameters (calculated using the submitted data), and then to crypt the hole ajax request into one string.
Somthing like sRequest=459fdjnfdw4r908vn....
sRequests holds my data (sUser=user&sPass=pass&iCheck=34564).
Edit: My client code was not public, compiled to an app.
I am using nodejs to write an image upload service. Paying clients will be able to send an image file to my endpoint that I have set up on my server. However, when every request comes in, I need to confirm that it is actually a paying client making the request. I thought about having the client give me their domain name and I would just check the referer header. However, someone could easily spoof the referer header and use my service without paying. How do SaaS developers face this technical problem? Is it possible to fix this without requiring my clients to have some server side code?
Are you building an external image hosting service for websites or is it to share something that HAS to be private and SECURE? If it is the former then read ahead.
Of course, the header can be spoofed. Here's why you should not worry about it:
Alternative is ugly: To build a secure provisioning service, you will have to develop some kind of token system that the website owner implements at his end as well. Chances are, he would not sign up with you because there are simpler alternatives available.
Spoofing will have to be done on client side. Very few "users" will actually do this. Two geeks spoofing headers on their own machine will not make a big difference to you. If they write some proxy or middle ware that does this work automatically and many people start using it, it could be a problem. However this is not very likely.
Guess you already know, but since you haven't mentioned - it is called Hotlinking. Google this topic to find more resources.
You cannot authenticate a browser with a referrer header.
If you want to authenticate an individual, then you will likely need a login system that they provide credentials to (username/pwd) and you check those against your allowed user base. If they pass, then you set a certain type of cookie in the browser that indicates they are a legit user. Subsequent requests from this user will contain that cookie which you can check on every request.
The cookie needs to be something that you create that you can verify that cannot easily be guessed or forged (like a session or an encrypted token from your server). You would typically set an expiration on the cookie after some time period of time so that the user has to login again.
I could do with some help on my REST API. I'm writing a Node.js app which is using Express, MongoDB and has Backbone.js on the client side. I've spent the last two days trying to work out all of this and not having much luck. I've already checked out:
Securing a REST API
Securing my REST API with OAuth while still allowing authentication via third party OAuth providers (using DotNetOpenAuth)
http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/
http://tesoriere.com/2011/10/10/node.js-getting-oauth-up-and-working-using-express.js-and-railway.js/
I want to keep my backend and frontend as separate as possible so I thought about using a carefully designed REST API would be good. My thinking is that if I ever get round to developing an iPhone app (or something else like that), it could use the API to access data.
BUT, I want this to be secure. A user has logged into my web app and I want to ensure my API is secure. I read about OAuth, OAuth 2.0, OpenID, Hmac, hashes etc... I want to avoid using external logging in (Facebook/Twitter/etc) I want the registering and logging in to be on my app/server.
...but I'm still confused here. Maybe it's late at night or my brain is just fried, but I could really do with some steps on what to do here. What are the steps for me to create a secure API?
Any help, any information, any examples, steps or anything would be great. Please help!
In order of increasing security / complexity:
Basic HTTP Auth
Many API libraries will let you build this in (Piston in Django for example) or you can let your webserver handle it. Both Nginx and Apache can use server directives to secure a site with a simple b64encoded password. It's not the most secure thing in the world but it is at least a username and password!
If you're using Nginx you can add a section to your host config like so:
auth_basic "Restricted";
auth_basic_user_file /path/to/htpasswd;
(Put it in your location / block)
Docs: http://wiki.nginx.org/HttpAuthBasicModule
You'll need to get the python script to generate that password and put the output into a file: http://trac.edgewall.org/browser/trunk/contrib/htpasswd.py?format=txt
The location of the file doesn't matter too much as long as Nginx has access to it.
HTTPS
Secure the connection from your server to the app, this is the most basic and will prevent man in the middle attacks.
You can do this with Nginx, the docs for it are very comprehensive: http://wiki.nginx.org/HttpSslModule
A self-signed certificate for this would be fine (and free!).
API Keys
These could be in any format you like but they give you the benefit of revoking access should you need to. Possibly not the perfect solution for you if you're developing both ends of the connection. They tend to be used when you have third parties using the API, eg Github.
OAuth
OAuth 2.0 is the one to go with here. While I don't know the underlying workings of the spec it's the defacto standard for most authentication now (Twitter, Facebook, Google, etc.) and there are a ton of libraries and docs to help you get those implemented. That being said, it's usually used to authenticate a user by asking a third party service for the authentication.
Given that you doing the development both ends it would probably be enough to put your API behind Basic HTTP Auth and serve it over HTTPS, especially if you don't want to waste time messing around with OAuth.
Here's a different way of thinking about it:
Let's suppose for a moment that you're not using an API. Your user logs into the app, providing some credentials, and you give a cookie or similar token of some sort to the user, which you use to identify that user has logged in. The user then requests a page containing restricted information (or creating/modifying/deleting it), so you check that this token to ensure that the user is allowed to view that information.
Now, it sounds to me that the only thing you're changing here is the way that information is delivered. Instead of delivering the information as rendered HTML, you're returning the information as JSON and rendering it on the client side. Your AJAX requests to the server will carry that same logged-in token as before, so I suggest just checking that token, and restricting the information down to 'just what the user is allowed to know' in the same way.
Your API is now as secure as your login is - if anyone was to know the token necessary for accessing the api, they would also be logged into the site and have access to all the information anyway. Best bit is, if you've already implemented login, you've not really had to do any more work.
The point of systems such as OAuth is to provide this 'logging in' method, usually from a third party application and as a developer. This would potentially be a good solution for an iPhone app or similar, but that's in the future. Nothing wrong with the API accepting more than one authentication method!
The answers so far do a great job of explaining, but don't give any actual steps. I came across this blog post that goes into great detail about how to create and manage tokens securely with Node + Passport.
http://aleksandrov.ws/2013/09/12/restful-api-with-nodejs-plus-mongodb/
Tips valid for securing any web application
If you want to secure your application, then you should definitely start by using HTTPS instead of HTTP, this ensures a creating secure channel between you & the users that will prevent sniffing the data sent back & forth to the users & will help keep the data exchanged confidential.
You can use JWTs (JSON Web Tokens) to secure RESTful APIs, this has many benefits when compared to the server-side sessions, the benefits are mainly:
1- More scalable, as your API servers will not have to maintain sessions for each user (which can be a big burden when you have many sessions)
2- JWTs are self contained & have the claims which define the user role for example & what he can access & issued at date & expiry date (after which JWT won't be valid)
3- Easier to handle across load-balancers & if you have multiple API servers as you won't have to share session data nor configure server to route the session to same server, whenever a request with a JWT hit any server it can be authenticated & authorized
4- Less pressure on your DB as well as you won't have to constantly store & retrieve session id & data for each request
5- The JWTs can't be tampered with if you use a strong key to sign the JWT, so you can trust the claims in the JWT that is sent with the request without having to check the user session & whether he is authorized or not, you can just check the JWT & then you are all set to know who & what this user can do.
Node.js specific libraries to implement JWTs:
Many libraries provide easy ways to create & validate JWTs, for example: in node.js one of the most popular is jsonwebtoken, also for validating the JWTs you can use the same library or use express-jwt or koa-jwt (if you are using express/koa)
Since REST APIs generally aims to keep the server stateless, so JWTs are more compatible with that concept as each request is sent with Authorization token that is self contained (JWT) without the server having to keep track of user session compared to sessions which make the server stateful so that it remembers the user & his role, however, sessions are also widely used & have their pros, which you can search for if you want.
One important thing to note is that you have to securely deliver the JWT to the client using HTTPS & save it in a secure place (for example in local storage).
You can learn more about JWTs from this link