Implementing SSE (Server Sent Events) security - server-sent-events

I am little new to SSE - server sent events implementation.
What I am trying to do is: to maintain a security check before connecting to SSE urls.
For ex- I have an SSE url which the clients will connect to , through EventSource:
new EventSource("http://my.example.com/deviceData");
So, not every client should be able to connect to it. I have to restrict it to some clients. How can I do that?
A code sample will be really helpful.

If the restriction is by IP, your server-side script can look at the headers and reject based on that. (It could also reject based on any of the other headers, but most of them can be forged, e.g. user-agent.)
If you are after the using logging in, you should use cookies. The simplest way is to have a login form on my.example.com that validates the user, and sends back a cookie. That cookie will then be sent to your SSE script, which can use its contents to validate the user. (If using this approach, you may also want to use https URLs: make sure both the login form and the SSE script are both on https, in that case.)

Related

Track a client through HTTP request

In case of HTTP requests like HEAD / GET / POST etc, which information of client is received by the server?
I know some of the info includes client IP, which can be used to block a user in case of, lets say, too many requests.
Another information of use would be user-agent, which is different for browsers, scripts, curl, postman etc. (Of course client can change default by setting request headers, but thats alright)
I want to know which other parameters can be used to identify a client (or define some properties)? Does the server get the mac address somehow?
So, is there a possibility that just by the request, it is identifiable that this request is being done by a "bot" (python or java code, eg.) vs a genuine user?
Assume there is no token or any such secret shared between client-server so there is no session...each subsequent request is independent.
The technique you are describing is generally called fingerprinting - the article covers properties and techniques. Depending on the use there are many criticisms of it, as it bypasses a users intention of being anonymous. In all cases it is a statistical technique - like most analytics.
Putting your domain behind a service like cloudflare might help prevent some of those bots from hitting your server. Other than a service like that, setting up a reCAPTCHA would block bots from accessing any pages behind it.
It would be hard to detect bots using solely HTTP because they can send you whatever headers they want. These services use other techniques to try and detect and filter out the bots, while allowing real users to access the site.
I don't think you can rely on any HTTP request header, because a client might not send it to the server, and/or there might be proxies between the client and the server that strip or alter the request headers.
If you just want to associate a unique ID to an HTTP request, you could generate an ID on your backend. For example, the JavaScript framework Hapi.js computes a request ID using this code:
new Date() + '-' + process.pid + '-' + Math.floor(Math.random() * 0x10000)
You might not even need to generate an ID manually. For example, if your app is on AWS and there is an Application Load Balancer in front of your backend, the incoming request will have the custom header X-Amzn-Trace-Id.
As for distinguishing between requests made by human clients and bots, I think you could adopt a "time trap" approach like the one described in this answer about honeypots for spambots.
HTTP request headers are not a good way to track users that use your site. This is because users can edit these headers and the server has no way to verify their authenticy. Also, in the case of the IP Address, it can change during a session if, for example, a user is on a mobile network.
My suggestion is using a cookie with a unique, random id, given to the user the first time they land on a page of your site. Keep in mind that the user can still edit/remove this cookie, so it isn't a perfect method. If you can force the user to login, then you could track the user with their session token.

Sending passwords through GET request

I have an app that requires users to enter database passwords. These passwords will not be saved on the server, and the server does not need to remember anything about the database after the request. If it's my understanding, most web servers will log get requests, and the browser can as well (does it do this even for fetch() requests?). I do not want to put databases at risk, but I also understand that you should not use a body in GET requests.
I am also not creating resources, so from what I also understand, I should not be using a POST request. Is there a safe way to send a get request with the password (over https) that makes sure it is not logged on the server? This would be an app that anyone could start - so I have no idea what their server configuration could be so I couldn't specifically disable it on one server to ignore it.
so from what I also understand, I should not be using a POST request.
Your understanding is incorrect. POST is the appropriate verb when none of the other verbs make sense. From the spec:
The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics.
Put simply, that means POST does whatever the service says it does. It isn't safe, idempotent, or cacheable so there are disadvantages to just using it for everything, but the intent is for it to be the catch-all verb.
You should not use GET because, as you mentioned, you should not include a body and URLs often get logged, which would expose your credentials.
If the client for your app is going to be a browser you can just use https only cookies to handle the authentication flow. In case if you want it to extend or use it in any other type of client, you can use the Authorization HTTP header.

Symfony2 - Check server-server request

I need to know when a request comes from a browser and when it comes from a server.
I have created an API and a listener to onKernelRequest event, I need to know what kind of request I received to execute a function or other.
How can I do this on Symfony 2.7?
A “server“ is an HTTP client just as a browser is. They only handle your websites response differently. So there’s no way to be sure who you are talking to. You can only check for a number of indicators.
You can examine the HTTP headers in the Request object. Your best bet would probably be the User-Agent header. But a non-browser could just as well fake the user agent header of an actual browser, so you’d only detect them if they want you to. And you’d have to prepare a list of user agents that you’d consider “servers“.

It is possible to 'Set-Cookie's for every request received in Ruby on Rails 3?

I would like to load cookies everytime and everywhere in my website because when my RoR application receives and accepts an "external" HTTP request (ex: REST API), cookies are not loaded (see RFC2109). So their values are inaccessible.
Cookies are accessible only when the HTTP request is made "internally" in my application.
new_cookies = {"Cookie" => "mycookie=1234;myothercookie=4567"}
Net::HTTP.get( URI.parse( http: //app1.website.com/users ), new_cookies)
All browsers will automatically send any cookies you set from your domain, you can check them simply by calling request.cookies from any controller method. It doesn't matter if the request was initiated from within your application (such as a 302 redirect) or not.
I just tried this with Firecookie:
Created a cookie "mycoolcookie" for the domain ".stackoverflow.com"
Went to stackoverflow.com, firebug showed that the cookie was sent in the request header.
Went to meta.stackoverflow.com, firebug showed that the cookie was sent in the request header.
Went to chat.stackoverflow.com, firebug showed that the cookie was sent in the request header.
A cookie is sent automatically by the browser, the server can never request for a cookie to be sent to it.
REST APIs are generally stateless, therefore you should avoid the use of server-side sessions or client-side cookies. If you want to indicate that a user only grabs resources belonging to them, use the Rails nested resources approach, that results in a call like:
http://abc.com/user/user001/books
For all books that belong to user001.
If you are looking to implement security, first you have to use HTTPS instead of HTTP. For the actual implementation you can use Basic Authentication and set the username/password in the request header or you can use something like OAuth which sets up a token for the user that they pass in with each request.

How to send password securely over HTTP?

If on a login screen user submits a form with their username and password, the password is sent in plain text (even with POST, correct me if I am wrong).
What is the right way to protect the user and his password against the third party who might be eavesdropping on the communication data?
I am aware that HTTPS is a solution to the problem, but is there any way to ensure at least some level of security using the standard HTTP protocol (POST request)? (perhaps using javascript in some way)
What I was about was a page - that is a PHP-generated login page, which is of course sent to users in HTTP GET request as an HTML file. There is no (#Jeremy Powel) connection established between the server and the client so I can't create such a handshaking protocol. And I want the complete process to be transparent to the user - he wants to submit a password, not deal with cryptography.
Using HTTP with SSL will make your life much easier and you can rest at ease. Very smart people (smarter than me at least!) have scrutinized this method of confidential communication for years.
Secure authentication is a broad topic. In a nutshell, as #jeremy-powell mentioned, always favour sending credentials over HTTPS instead of HTTP. It will take away a lot of security related headaches.
TSL/SSL certificates are pretty cheap these days. In fact if you don't want to spend money at all there is a free letsencrypt.org - automated Certificate Authority.
You can go one step further and use caddyserver.com which calls letsencrypt in the background.
Now, once we got HTTPS out of the way...
You shouldn't send login and password via POST payload or GET parameters. Use an Authorization header (Basic access authentication scheme) instead, which is constructed as follows:
The username and password are combined into a string separated by a
colon, e.g.: username:password
The resulting string is encoded using
the RFC2045-MIME variant of Base64, except not limited to 76
char/line.
The authorization method and a space i.e. "Basic " is then
put before the encoded string.
source: Wikipedia: Authorization header
It might seem a bit complicated, but it is not.
There are plenty good libraries out there that will provide this functionality for you out of the box.
There are a few good reasons you should use an Authorization header
It is a standard
It is simple (after you learn how to use them)
It will allow you to login at the URL level, like this: https://user:password#your.domain.com/login (Chrome, for example will automatically convert it into Authorization header)
IMPORTANT:
As pointed out by #zaph in his comment below, sending sensitive info as GET query is not good idea as it will most likely end up in server logs.
The Authorization header value is traditionally a base64-encoded username/password. Base64 is not encryption. The original value can be obtained by an on-path attacked using a simple base64-decode.
You can use a challenge response scheme. Say the client and server both know a secret S. Then the server can be sure that the client knows the password (without giving it away) by:
Server sends a random number, R, to client.
Client sends H(R,S) back to the server (where H is a cryptographic hash function, like SHA-256)
Server computes H(R,S) and compares it to the client's response. If they match, the server knows the client knows the password.
Edit:
There is an issue here with the freshness of R and the fact that HTTP is stateless. This can be handled by having the server create a secret, call it Q, that only the server knows. Then the protocol goes like this:
Server generates random number R. It then sends to the client H(R,Q) (which cannot be forged by the client).
Client sends R, H(R,Q), and computes H(R,S) and sends all of it back to the server (where H is a cryptographic hash function, like SHA-256)
Server computes H(R,S) and compares it to the client's response. Then it takes R and computes (again) H(R,Q). If the client's version of H(R,Q) and H(R,S) match the server's re-computation, the server deems the client authenticated.
To note, since H(R,Q) cannot be forged by the client, H(R,Q) acts as a cookie (and could therefore be implemented actually as a cookie).
Another Edit:
The previous edit to the protocol is incorrect as anyone who has observed H(R,Q) seems to be able to replay it with the correct hash. The server has to remember which R's are no longer fresh. I'm CW'ing this answer so you guys can edit away at this and work out something good.
If your webhost allows it, or you will need to deal with sensitive data, then use HTTPS, period. (It's often required by the law afaik).
Otherwise if you want to do something over HTTP. I would do something like this.
The server embeds its public key into the login page.
The client populates the login form and clicks submit.
An AJAX request gets the current timestamp from the server.
Client side script concatenates the credentials, the timestamp and a salt (hashed from analog data eg. mouse movements, key press events), encrypts it using the public key.
Submits the resulting hash.
Server decrypts the hash
Checks if the timestamp is recent enough (allows a short 5-10 second window only). Rejects the login if the timestamp is too old.
Stores the hash for 20 seconds. Rejects the same hash for login during this interval.
Authenticates the user.
So this way the password is protected and the same authentication hash cannot be replayed.
About the security of the session token. That's a bit harder. But it's possible to make reusing a stolen session token a bit harder.
The server sets an extra session cookie which contains a random string.
The browser sends back this cookie on the next request.
The server checks the value in the cookie, if it's different then it destroys the session, otherwise all is okay.
The server sets the cookie again with different text.
So if the session token got stolen, and a request is sent up by someone else, then on the original user's next request the session will be destroyed. So if the user actively browsing the site, clicking on links often, then the thief won't go far with the stolen token. This scheme can be fortified by requiring another authentication for the sensitive operations (like account deletion).
EDIT: Please note this doesn't prevent MITM attacks if the attacker sets up their own page with a different public key and proxies requests to the server.
To protect against this the public key must be pinned in the browser's local storage or within the app to detect these kind of tricks.
About the implementation: RSA is probably to most known algorithm, but it's quite slow for long keys. I don't know how fast a PHP or Javascript implementation of would be. But probably there are a faster algorithms.
You can use SRP to use secure passwords over an insecure channel. The advantage is that even if an attacker sniffs the traffic, or compromises the server, they can't use the passwords on a different server. https://github.com/alax/jsrp is a javascript library that supports secure passwords over HTTP in the browser, or server side (via node).
I would use a server-side and client-side Diffie-Hellman key exchange system with AJAX or multiple form submits(I recommend the former), although I don't see any good implementations thereof on the internet. Remember that a JS library can always be corrupted or changed by MITM. Local storage can be used to help combat this, to an extent.
HTTPS is so powerful because it uses asymmetric cryptography. This type of cryptography not only allows you to create an encrypted tunnel but you can verify that you are talking to the right person, and not a hacker.
Here is Java source code which uses the asymmetric cipher RSA (used by PGP) to communicate:
http://www.hushmail.com/services/downloads/
you can use ssl for your host there is free project for ssl like letsencrypt
https://letsencrypt.org/
Using https sounds best option here (certificates are not that expensive nowadays). However if http is a requirement, you may use some encription - encript it on server side and decript in users browser (send key separately).
We have used that while implementing safevia.net - encription is done on clients (sender/receiver) sides, so users data are not available on network nor server layer.

Resources