I know it as secure-token URL, maby there is another name out there. But I think you all know it.
Its a teqniuque mostly applied if you want to restrict content delivery to a certain client, that you have handed a specific url in advance.
You take a secret token, concatenate it with the resource you want to protect, has it and when the client requests the this URL on one of your server, the hash is re-constructed from the information gathered from the request and the hash is compared. If its the same, the content is delivered, else the user gets redirected to your webseite or something else.
You can also put a timestamp in the has to put a time to live on the url, or include the users ip adress to restrict the delivere to his connection.
This teqnique is used by Amazon (S3 and Cloudfront),Level 3 CDN, Rapidshare and many others. Its also a basic part of http digest authentication, altough there is it taken a step further with link invalidation and other stuff.
Here is a link to the Amazon docs if you want to know more.
Now my concerns with this method is that if one person cracks one token of your links, the attacker gets your token plain-text and can sign any URL in your name himself.
Or worse, in the case of amazon, access your services on an administrative scope.
Granted, the string hashed here is usually pretty long. And you can include a lot of stuff or even force the data to have a minimum length by adding some unnecessary data to the request. Maby some pseudo variable in the URL that is not used, and fill it up with random data.
Therefore brute force attacks to crack the sha1/md5 or whatever you use hash are pretty hard. But protocol is open, so you only have to fill in the gap where the secret token is and fill up the rest with the data known from the requst. AND today hardware is awesome and can calculate md5s at a rate of multiple tens of megabytes per second. This sort of attack can be distributed to a computing cloud and you are not limited to something like "10 tries per minute by a login server or so" which makes hashing approaches usually quite secure. And now with amazon EC2 you can even rent the hardware for short time (beat them with their own weapons haha!)
So what do you think? Do my concerns have a basis or am I paranoic?
However,
I am currently designing an object storage cloud for special needs (integrated media trans coding and special delivery methods like streaming and so on).
Now level3 introduced an alternative approach to secure token urls. Its currently beta and only open to clients who specifically request it. They call it "Proxy authentication".
What happens is that the content-delivery server makes a HEAD request to a server specified in your (the client's) settings and mimics the users request. So the same GET path and IP Address (as x_forwarder) is passed. You respond with a HTTP status code that tells the server to go a head with the content delivery or not.
You also can introduce some secure-token process into this and you can also put more restrictions on it. Like let a URL only be requested 10 times or so.
It obviously comes with a lot of overhead because additional request and calculations take place, but I think its reasonable and I don't see any caveats with it. Do you?
You could basically reformulate your question to: How long a secret token is needed to be safe.
To answer this consider the number of possible characters (alphanumeric + uppercase is is already 62 options per character). Secondly ensure that the secret token is random, and not in a dictionary or something. Then for instance if you would take a secret token of 10 characters long, it would take 62^10 (= 839.299.365.868.340.224 )attempts to bruteforce (worstcase; average case would be half of that of course). I wouldn't really be scared of that, but if you are, you could always ensure that the secret token is at least 100 chars long, in which case it takes 62^100 attempts to bruteforce (which is a number of three lines in my terminal).
In conclusion: just take a token big enough, and it should suffice.
Of course proxy authentication does offer your clients extra control, since they can way more directly control who can look and not, and this would for instance defeat emailsniffing as well. But I don't think the bruteforcing needs to be a concern given a long enough token.
It's called MAC as far as I understand.
I don't understand what's wrong with hashes. Simple calculations show that a SHA-1 hash, 160 bits, gives us very good protection. E.g. if you have a super-duper cloud which does 1 billion billions attempts per second, you need ~3000 billions billions years to brute force it.
You have many ways to secure a token :
Block IP after X failed token decoding
Add a timestamp in your token (hashed or crypted) to revoke the token after X days or X hours
My favorite : use a fast database system such as Memcached or better : Redis to stokre your tokens
Like Facebook : generate a token with timestamp, IP etc... and crypt it !
Related
I'm thinking whether the following way is a good way to completely and totally prevent ddos on my server. My idea is to use the same mechanism of cryptocurrency mining (bitcoin, with sha256 or any other hash) to prevent DDOS.
Note: I'm not suggesting to mine cryptocurrency per se. I'm suggesting to use the same mechanism to avoid Sybil attacks.
Why does idea look appealing to me? Because creating a mined hash is expensive, but verifying it is super-cheap. it costs only calculating a hash once.
What does mining mean, in a nutshell? It means that there's a specific chunk of data (say a session id, or a JWT token, that can be stored in the server in a performant NoSQL server), and the user (or the miner in cryptocurrency) has to create a hash that matches certain criteria. For example, if we use SHA256, we can define the difficulty as the required number of the leading zeros in the 256-bit resulting number from the hash. More zeros make the probability of finding that hash more difficult.
How does it work?: A user would take the session token (which is created by the server), and combine it with a nonce (number used once), and calculate the hash in their frontend (through WASM, or otherwise with javascript). Since the user cannot reverse-engineer SHA256, all he can do is keep changing the nonce again, and again and again, until he finds a nonce that creates a hash that satisfies the required difficulty.
The graph shows the probability of finding a block (finding the correct nonce) in Bitcoin, where the difficulty is chosen to make it 10 minutes. Changing the difficulty will shift this curve and change its width proportionally.
How long does it take the server to verify? Practically zero. Just calculate the hash once and ensure that it matches the given difficulty, and that authorizes the user to make any anonymous request. Notice that none of this requires authentication with usernames and password. This is all anonymous. Authenticated users don't need to do this as their credentials can be banned from the system. This is all for anonymous users (and possibly attackers).
The result: The user will have to calculate this hash with this difficulty before making any request to the server. Once the user succeeds, the mined authentication token can be stored in a cookie to be reused by the user. If the user fails to provide the requested hash, his connection request will be abruptly reject, and thus preventing a DDOS attack with sock-puppets.
ASIC resistance: Using SHA256 is not recommended because there's specialized hardware that can calculate it very fast, leading to a possible coordinated attack. There are hashes that are hard to print on hardware, such as Scrypt and Argon2.
Choosing the difficulty: The difficulty can be static (which I wouldn't recommend), or can be dynamic to change with the load on the network. When a high network load exists, the required difficulty is increased. This basically will act as a filter and protect the network during DDOS attack times, and never affect the users, as users normally wouldn't care to wait 10 seconds to create a session. In case of really high load, the users can either choose to compute the expensive nonce, or come back later. The hosting company also can decide whether an expansion of the infrastructure is required based on the difficulty chart over time.
Is this a sound plan to protect against DDOS on websocket and similar public protocols? I would like to implement this on my server.
Since a DDOS operates from multiple systems on multiple connections it is easy to counteract if you just write a script that will request a new SHA256 hash from the server for each individual connection will clog your server. They do not need to reverse engineer but just generate 'session tokens' for each individual connection requesting access to the server.
It should work in some way and protect from simple attacks. But you can improve it, by requesting dynamic hash difficulty on different requests.
For example, you have 2 pages, one displays data with specific record in db (by using primary key), second does difficult search, and sometimes there is no necessary index in db to do search fast, or page displays a lot of results. Attacker would like to DDOS second page and make the search as slow as possible.
You can setup low difficulty for first page, and high for second. The main idea can be: If you want to take x CPU time on server, spend c * x of your CPU time.
If you request hash only once, attacker can calculate necessary nonce and do million of requests by using single cookie.
My website collect user comments about some images. Non registered user can click "Good" button. What is the best way to remeber by system the user choice? One person can click "Good" only one time. Cookies? Session? Other way?
First you have to realise that all session techniques are cookie based. That is all good techniques. That means that they all have the downside that they will not work where cookies do not work user choices will be forgotten. In those (hopefully rare) cases you could store these choices either in the URL or as a CGI parameter. In any cases you can not make it really secure.
That being said, you have tradeoffs to consider.
Cookies
If you use purely cookie based storage then you could be limited in the number of user choices that can be stored in cookies under a single domain name. RFC 6265 states some SHOULDs regarding those and implementation matching these will give you at most 200KB which should be quite enough. Older RFC 2965 says implementations should give you 80KB. Also remember that the browser will send you the cookie for every request to your website. This could mean slow browsing for your users.
Assuming a 24 bits image ID (16 million possible images), base64 encoded to 4 bytes you can pack close to 20,000 choices into cookies. For 32 bits image ID, encoded to 6 bytes you still get more than 10,000 choices into your cookies.
When cookies prove too cumbersome, say after 1,000 votes you could switch the browser into the session technique… Or consider that he will never get to this without having registered ;-)
Sessions
If you decide to store the user choices in the session then you will have to dedicate some storage area on the server. The downsides are that:
you have no safe way to know when a session is not used anymore. Therefore you need some mecanism to reclaim unused sessions, typically expiring sessions after a fixed amount of inactivity,
it is more difficult to scale if and when you want to distribute the load amongs multiple HTTP servers.
You create a unique "token" that you save as cookie (hash of IP + timestamp for example). This value is also beeing saved to the database in conjunction with the vote.
In an effort to increase performance, I was thinking of trying to eliminate a plain 'session cookie', but encrypt all the information in the cookie itself.
A very simple example:
userid= 12345
time=now()
signature = hmac('SHA1',userid + ":" + time, secret);
cookie = userid + ':' + time + ':' + signature;
The time would be used for a maximum expirytime, so cookies won't live on forever.
Now for the big question: is this a bad idea?
Am I better off using AES256 instead? In my case the data is not confidential, but it must not be changed under any circumstances.
EDIT
After some good critique and comments, I'd like to add this:
The 'secret' would be unique per-user and unpredictable (random string + user id ?)
The cookie will expire automatically (this is done based on the time value + a certain amount of seconds).
If a user changes their password, (or perhaps even logs out?) the secret should change.
A last note: I'm trying come up with solutions to decrease database load. This is only one of the solutions I'm investigating, but it's kind of my favourite. The main reason is that I don't have to look into other storage mechanism better suited for this kind of data (memcache, nosql) and it makes the web application a bit more 'stateless'.
10 years later edit
JWT is now a thing.
A signed token is a good method for anything where you want to issue a token and then, when it is returned, be able to verify that you issued the token, without having to store any data on the server side. This is good for features like:
time-limited-account-login;
password-resetting;
anti-XSRF forms;
time-limited-form-submission (anti-spam).
It's not in itself a replacement for a session cookie, but if it can eliminate the need for any session storage at all that's probably a good thing, even if the performance difference isn't going to be huge.
HMAC is one reasonable way of generating a signed token. It's not going to be the fastest; you may be able to get away with a simple hash if you know about and can avoid extension attacks. I'll leave you to decide whether that's worth the risk for you.
I'm assuming that hmac() in whatever language it is you're using has been set up to use a suitable server-side secret key, without which you can't have a secure signed token. This secret must be strong and well-protected if you are to base your whole authentication system around it. If you have to change it, everyone gets logged out.
For login and password-resetting purposes you may want to add an extra factor to the token, a password generation number. You can re-use the salt of the hashed password in the database for this if you like. The idea is that when the user changes passwords it should invalidate any issued tokens (except for the cookie on the browser doing the password change, which gets replaced with a re-issued one). Otherwise, a user discovering their account has been compromised cannot lock other parties out.
I know this question is very old now but I thought it might be a good idea to update the answers with a more current response. For anyone like myself who may stumble across it.
In an effort to increase performance, I was thinking of trying to
eliminate a plain 'session cookie', but encrypt all the information in
the cookie itself.
Now for the big question: is this a bad idea?
The short answer is: No it's not a bad idea, in fact this is a really good idea and has become an industry standard.
The long answer is: It depends on your implementation. Sessions are great, they are fast, they are simple and they are easily secured. Where as a stateless system works well however, is a bit more involved to deploy and may be outside the scope of smaller projects.
Implementing an authentication system based on Tokens (cookies) is very common now and works exceedingly well for stateless systems/apis. This makes it possible to authenticate for many different applications with a single account. ie. login to {unaffiliated site} with Facebook / Google.
Implementing an oAuth system like this is a BIG subject in and of itself. So I'll leave you with some documentation oAuth2 Docs. I also recommend looking into Json Web Tokens (JWT).
extra
A last note: I'm trying come up with solutions to decrease database
load. This is only one of the solutions I'm investigating
Redis would work well for offloading database queries. Redis is an in memory simple storage system. Very fast, ~temporary storage that can help reduce DB hits.
Update: This answer pertains to the question that was actually asked, not to an imagined history where this question was really about JWT.
The most important deviations from today's signed tokens are:
The question as originally posed didn't evince any understanding of the need for a secret in token generation. Key management is vital for JWT.
The questioner stated that they could not use HTTPS, and so they lacked confidentiality for the token and binding between the token and the request. In the same way, even full-fledged JWT can't secure a plain HTTP request.
When the question was revised to explain how a secret could be incorporated, the secret chosen required server-side state, and so fell short of the statelessness provided by something like JWT.
Even today, this homebrew approach would be a bad idea. Follow a standard like JWT, where both the scheme and its implementations have been carefully scrutinized and refined.
Yes, this is a bad idea.
For starters, it's not secure. With this scheme, an attacker can generate their own cookie and impersonate any user.
Session identifiers should be chosen from a large (128-bit) space by a cryptographic random number generator.
They should be kept private, so that attackers cannot steal them and impersonate an authenticated user. Any request that performs an action that requires authorization should be tamper-proof. That is, the entire request must have some kind of integrity protection such as an HMAC so that its contents can't be altered. For web applications, these requirements lead inexorably to HTTPS.
What performance concerns do you have? I've never seen a web application where proper security created any sort of hotspot.
If the channel doesn't have privacy and integrity, you open yourself up to man-in-the-middle attacks. For example, without privacy, Alice sends her password to Bob. Eve snoops it and can log in later as Alice. Or, with partial integrity, Alice attaches her signed cookie to a purchase request and sends them to Bob. Eve intercepts the request and modifies the shipping address. Bob validates the MAC on the cookie, but can't detect that the address has been altered.
I don't have any numbers, but it seems to me that the opportunities for man-in-the-middle attacks are constantly growing. I notice restaurants using the wi-fi network they make available to customers for their credit-card processing. People at libraries and in work-places are often susceptible to sniffing if their traffic isn't over HTTPS.
You should not reinvent the wheel. The session handler that comes with your development platform far is more secure and certainly easier to implement. Cookies should always be very large random numbers that links to server side data. A cookie that contains a user id and time stamp doesn't help harden the session from attack.
This proposed session handler is more vulnerable to attack than using a Cryptographic nonce for each session. An attack scenario is as follows.
It is likely that you are using the same secret for your HMAC calculation for all sessions. Thus this secret could be brute forced by an attacker logging in with his own account. By looking at his session id he can obtain everything except for the secret. Then the attacker could brute force the secret until the hmac value can be reproduced. Using this secret he can rebuild a administrative cookie and change his user_id=1, which will probably grant him administrative access.
What makes you think this will improve performance vs. secure session IDs and retrieving the userid and time information from the server-side component of the session?
If something must be tamper-proof, don't put it in the toddlers' hands. As in, don't give it to the client at all, even with the tamper-proof locking.
Ignoring the ideological issues, this looks pretty decent. You don't have a nonce. You should add that. Just some random garbage that you store along with the userid and time, to prevent replay or prediction.
I want to create a portal website for log-in, news and user management. And another web site for a web app that the portal redirects to after login.
One of my goals is to be able to host the portal and web-app on different servers. The portal would transmit the user's id to the web-app, once the user had successfully logged in and been redirected to the web app. But I don't want people to be able to just bypass the login, or access other users accounts, by transmitting user ids straight to the web app.
My first thought is to transmit the user id encrypted as a post variable or query string value. Using some kind of public/private key scenario, and adding a DateTime stamp to key to make it vary everytime.
But I haven't done this kind of thing before, so I'm wondering if there aren't better ways to do this.
(I could potentially communicate via database, by having the portal store the user id with a key in a database and passing that key to the web app which uses it to get the user id from that database. But that seems crazy.)
Can anyone give a way to do this or advice? Or is this a bad idea all-together?
Thanks for your time.
Basically, you are asking for a single-sign-on solution. What you describe sounds a lot like SAML, although SAML is a bit more advanced ;-)
It depends on how secure you want this entire thing to be. Generating an encrypted token with embedded timestamp still leaves you open to spoofing - if somebody steals the token (i.e. through a network sniffing) he will be able to submit his own request with the stolen token. Depending on the time to live you will give your token this time can be limited, but a determined hacker will be able to do this. Besides you cannot make time to live to small - you will be rejecting valid requests.
Another approach is to generate "use once" tokens. This is 'bullet proof' in terms of spoofing, but it requires coordination among all the servers within the server farm servicing your app, so that if one of them processed the token the other ones would reject it.
To make it really secure for the failover scenarios, etc. it would require some additional steps, so it all boils down to how secure you need it to be and how much you want to invest in building it up
I suggest looking at SAML
PGP would work but it might get slow on a high-traffic site
One thing I've done in the past is used a shared secret method. Some token that only myself and the other website operator knows concatenated to something identifying the user (like their user name), then hash that with a checksum algorithm such as SHA256 (you can use MD5 or SHA1 which usually are more available but they are much easier to break)
The other end should do the same thing as above. Take the passed identifying information and checksum it. Compare that to the passed checksum, if they match the login is valid.
For added security you could also concat the date or some other rotating key. Helps to run SSL on both sides as well.
In general, the answer resides somewhere in SHA256 / MD5 / SHA1 plus shared secret based on human actually has to think. If there is money somewhere, we may assume there are no limits to what some persons will do - I ran with [ a person ] in High School for a few months to observe what those ilks will do in practice. After a few months, I learned not to be running with those kind. Tediously avoiding work, suddenly at 4 AM on Saturday Morning the level of effort and analytical functioning could only be described as "Expertise" ( note capitalization ) There has to be a solution else sites like Google and this one would not stand the chance of a dandelion in lightning bolt.
There is a study in the mathematical works of cryptography whereby an institution ( with reputable goals ) can issue information - digital cash - that can exist on the open wire but does not reveal any information. Who would break them? My experience with [ person ]
shows that it is a study in socialization, depends on who you want to run with. What's the defense against sniffers if the code is already available more easily just using a browser?
<form type="hidden" value="myreallysecretid">
vis a vis
<form type="hidden" value="weoi938389wiwdfu0789we394">
So which one is valuable against attack? Neither, if someone wants to snag some Snake Oil from you, maybe you get the 2:59 am phone call that begins: "I'm an investor, we sunk thousands into your website. I just got a call from our security pro ....." all you can do to prepare for that moment is use established, known tools like SHA - of which the 256 variety is the acknowledged "next thing" - and have trace controls such that the security pro can put in on insurance and bonding.
Let alone trying to find one who knows how those tools work, their first line of defense is not talking to you ... then they have their own literature - they will want you to use their tools.
Then you don't get to code anything.
Obviously some sort of mechanism for limiting login attempts is a security requisite. While I like the concept of an exponentially increasing time between attempts, what I'm not sure of storing the information. I'm also interested in alternative solutions, preferrably not including captchas.
I'm guessing a cookie wouldn't work due to blocking cookies or clearing them automatically, but would sessions work? Or does it have to be stored in a database? Being unaware of what methods can/are being used so I simply don't know what's practical.
Use some columns in your users table 'failed_login_attempts' and 'failed_login_time'. The first one increments per failed login, and resets on successful login. The second one allows you to compare the current time with the last failed time.
Your code can use this data in the db to determine how long it waits to lock out users, time between allowed logins etc
Assuming google has done the necessary usability testing (not an unfair assumption) and decided to use captchas , I'd suggest going along with them.
Increasing timeouts is frustrating when I'm a genuine user and have forgotten my password (with so many websites and their associated passwords that happens a lot , especially to me)
Storing attempts in the database is the best solution IMHO since it gives you the auditing records of the security breach attempts. Depending on your application this may or may not be a legal requirement.
By recording all bad attempts you can also gather higher level information, such as if the requests are coming from one IP address (i.e. someone / thing is attempting a brute force attack) so you can block the IP address. This can be VERY usefull information.
Once you have determined a threshold, why not force them to request the email to be sent to their email address (i.e. similar to 'I have forgotten my password'), or you can go for the CAPCHA approach.
Answers in this post prioritize database centered solutions because they provide a structure of records that make auditing and lockout logic convenient.
While the answers here address guessing attacks on individual users, a major concern with this approach is that it leaves the system open to Denial of Service attacks. Any and every request from the world should not trigger database work.
An alternative (or additional) layer of security should be implemented earlier in the req/ res cycle to protect the application and database from performing lock out operations that can be expensive and are unnecessary.
Express-Brute is an excellent example that utilizes Redis caching to filter out malicious requests while allowing honest ones.
You know which userid is being hit, keep a flag and when it reaches a threshold value simply stop accepting anything for that user. But that means you store an extra data value for every user.
I like the concept of an exponentially increasing time between attempts, [...]
Instead of using exponentially increasing time, you could actually have a randomized lag between successive attempts.
Maybe if you explain what technology you are using people here will be able to help with more specific examples.
Lock out Policy is all well and good but there is a balance.
One consideration is to think about the consruction of usernames - guessable? Can they be enumerated at all?
I was on an External App Pen Test for a dotcom with an Employee Portal that served Outlook Web Access /Intranet Services, certain Apps. It was easy to enumerate users (the Exec /Managament Team on the web site itself, and through the likes of Google, Facebook, LinkedIn etc). Once you got the format of the username logon (firstname then surname entered as a single string) I had the capability to shut 100's of users out due to their 3 strikes and out policy.
Store the information server-side. This would allow you to also defend against distributed attacks (coming from multiple machines).
You may like to say block the login for some time say for example, 10 minutes after 3 failure attempts for example. Exponentially increasing time sounds good to me. And yes, store the information at the server side session or database. Database is better. No cookies business as it is easy to manipulate by the user.
You may also want to map such attempts against the client IP adrress as it is quite possible that valid user might get a blocked message while someone else is trying to guess valid user's password with failure attempts.