I've created a forum which uses a PHP session when logged in to determine the user id, and cookies for log-term login.
I suppose I have two questions:
Is this the best/securest method?
Cookies can be added manually via the address bar with javascript, which is a huge security risk. Is there any way around this?
Thanks!
First, make sure you are using https and not http. This will keep your traffic from getting sniffed and exploited.
Secondly, generate as random a value as possible to use as a token in the cookie. This is how many of the big sites do their user tracking. Have a map of token to user on the server side that tracks the identities. Remember: Anything that comes from the client is untrusted and could be tampered with.
Third, use an HMAC to make tampering much more difficult. You don't want users being able to brute force other tokens.
EDIT:
You may find these other SO questions/answers helpful as you build this system:
Long details about creating and using tokens (doesn't necessarily have to be a REST service to be applicable): REST Web Service authentication token implementation
Creating good tokens (don't use microtime): Is using microtime() to generate password-reset tokens bad practice
Related
A user logs in using default Laravel authentication, which puts an encrypted cookie in the browser, and saves the session in the database.
The user moves to a classic asp page, where I check the cookie value, get the hash, and call the laravel app back passing the session id hash.
Then I use that in laravel to see if there's an active session for that id, and if so I return true, so the user can be logged in, in classic asp.
On each page request in the classic app, I check the last_updated_time in the db and update it on each page. All logging in and out is done in laravel, and classic relies on the database to see if a session is active.
I would also call a public url to get sessions variables and add session variables using laravel, since it's all encrypted and using classic asp for this would be hard.
The only risk I see is session highjacking, but I don't think it's a higher risk than usual.
Is it important to lockdown the laravel URL I call to check if it's a valid session?
Am I missing a security hole here?
Is this method secure?
From what you've stated you probably haven't opened up any security holes. The session cookie is not itself encrypted on the users machine, but you are making sure it is encrypted between their machines and yours, as well as between each of your machines. You should make sure you've set the Secure Flag to help prevent the cookie being accidentally sent over traditional unencrypted transport (HTTP), but as stated, this doesn't effect storing the cookie itself.
That being said, you are essentially hijacking your own users sessions. While a hole might not be introduced now, you are potentially weakening the overall system, which could lead to hole in the future.
Is there a better way to do it?
This might well be a dumb question, but are you sure you need the session? If you're juggling credentials between servers, it sounds more like you want to use Access Tokens and scrap the session.
Using Access Tokens is similar to using sessions, but you need to make your services stateless. This means your no longer storing information about the logged in user any specific machine so you'll need to pull anything you need from the database every time they hit a server requiring that information.
This is a good thing in the long run as it's much easier to scale your services when you don't need to worry so much about where the session is and what's inside it.
OAuth 2.0 is widely used standard (Facebook, Twitter, Google), and was specifically designed to be easy to use. The RFC is complex, but there's a log of good guides out there don't worry.
The one slight down side (if you can call it that) to OAuth 2, is that it MUST happen over an encrypted connection. If your use case can not guarantee encryption over SSL or (preferably) TLS, then you should use OAuth 1.0 (WITH revision A) instead.
This is due to the fact that OAuth 2.0 exposes it's "secret" token in requests, where as OAuth 1.0 only ever uses it to provide a signature hash. If you take this route it's advisable to use someone else's library as the hash is very, specific.
Further Improvement
(Note: This section added after the answer was accepted)
One system I've been exploring recently is Json Web Tokens. These store information about the user to save each machine repeatedly looking it up in a database. Because the token is hashed with a secret, you can be sure that, so long as your secret isn't exposed, a valid token represents a successfully logged in user, without having to touch the database.
You should avoid putting anything too personal in the tokens if possible. If you must store private or secret information in the token, you can encrypt it, or you can use a reverse caching proxy to exchange the JWT for a traditional security token. This may initially seem to defeat the purpose, but it means some of your services may not need database access at all.
I'm no security expert but I don't see an issue with this. The packaged Laravel database session handler works the same way. The cookie contains a hash that references a record in the database. The session data is base64 encoded but that's neither here nor there. I think you could actually avoid rolling your own and just use Laravel's DatabaseSessionHandler.
Illuminate/Session/DatabaseSessionHandler
... I just read a little deeper into your question and noticed the part about the public URL to set and retrieve session data. I think this is a really bad idea. Mostly because it will provide an open door to the end user allowing them to read and write session data. This can only end badly.
Like I said above, the data is only base64 encoded so I believe you'll be able to parse, read and write that to your hearts content within asp.
Edit
Ok... I think this is the last edit. The data is php serialized and then base64 encoded. This question looks like it may help you to that end. If it doesn't and an API endpoint is the only way, find some way to block the end user from accessing it.
Aside from session-hijacking, no. This is the standard way applications interact on a internal basis. Of course there might be a better way to get at the data if you choose a different type of session store other than your database, Memcached for instance.
There are couple of things that can be done.
Make the channel HTTPS. It will make almost impossible to sniff on your transport layer.
Rather than making interactions with your cookie, you could use a JWT to get this task done. Which will help you to use the existing functionality in your system while connecting with ASP system as well. You can write a small REST web service which allows ASP to connect. You could use this lib. You can refer this article which will give you an idea how it should be done.
Please let me know if you need more information.
I want to build an API for users to build applications that easily interact with a site, and I was wondering what the best way to authenticate users would be.
Taking a look at other API's a lot of them have the user send the username and password as a GET parameter over a HTTPS connection. Is this the best way to go about it? Or are there other methods that I should look into or consider?
I've seen OAuth been tossed around and it looks like a good solution, but just for a simple API is it overkill?
You can use API key's. Generate a unique hash tied to an account upon request. Then check that the key is a valid key. As long as the API doesn't have any major security issues with someone using someone else's key then Authorization isn't needed. If there is a problem with someone using someone else's key then Authentication would be justified.
This is usually achieved with cookies.
The client sends their username and password with a POST request to your API (do not use GET, that's insecure). If the credentials are acceptable, then generate a random, unique session key, store it on your side and send it in a cookie back to the client (see setcookie()).
When the client now makes further requests, they send the session key cookie with the request. Check $_COOKIE for the session key if it matches a stored key on your side; if yes, that means the user authenticated.
Take note that this minimal example is vulnerable to brute-force attacks trying to guess valid session keys. You need to log invalid keys that clients send in their cookies and block their IP address for some period of time to prevent this.
Username / password in a GET isn't a great way to do this because you're potentially exposing the whole user account for hijacking even if the API has more limited functionality than logging into the site. So it's good practice to separate concerns between Web-site login and API access.
I'm not sure which case you're in but:
If the users are business customers of somekind who are embedding some type of widget or code in another website then it's probably best to use an API key which is scoped to the referrer domain (much like Google Maps does).
If they are end-users who won't know anything about the API but are going to be using Apps built by third parties then oAuth is likely to be your best bet, otherwise your users might literally be giving their usernames/passwords to unknown third parties. It's more complex but likely to be worth it in the long run.
To get a bunch of this stuff out of the box you can use something like 3scale (http://www.3scale.net) and it'll handle most of it for you (disclaimer, I work there so adjust for bias!) or there are open source libraries for oAuth in most languages (in PHP Zend-OAuth component might do the job for you).
I'm modifying an Android app that utilizes a webapp via a webview. Currently the the code base for the webapp is written in ColdFusion - so all the session management is done in CF. There are certain hooks in the webapp that force the Android app to do native functions and sometimes call external scripts in PHP.
These php scripts get data posted to them (userid, friendid, etc) - currently the php scripts just make sure there is valid data being posted, then process the request if the data is present and valid.
I am looking for ways to increase the security of these php scripts to prevent bots / malicious users from posting false data to these pages - at this point nothings stopping anyone sending a correct userid/friendid and having the script from executing.
Session management would be the first line of defense, but since the webapp is in a different language I can't use that - and sometimes the php scripts are on a different domain completely (same server though).
The other method I considered was on sign up creating a user token to associate with a user, and saving this on the Android side of things - then when requesting these php scripts send the userid and token. And verify the token for that user matches in the remote database - this would make it harder to guess posting credentials for malicious user. Clearly not the best because the token is stored locally and going over the wire, but I digress.
Question are there any better methods to use in order to protect these lone php scripts from being executed, with out the use of session management? Does my token idea make any sense?
Note: I can use SSL on any / all requests.
I know exactly what you need, if you're up to the task. Your API needs to impliment OAuth2.0.
What OAuth can provide you is a secure way to pass information to and from your service while making sure that all secret information is kept private and that only the correct people can access that information. It gives each user a unique signature.
OAuth is used by Facebook, Google, Twitter and more to give developers a secure way to access information while keeping everyone from doing things they shouldn't be doing.
OAuth has support for ColdFusion, Java, PHP, C#, dotNet, VB.net, LIST, Javascript, Perl, Python, Ruby, and more.
http://oauth.net/
Session management or OAuth are the best solutions, but not the easiest. An easier way is implementing a hashing algorithm in both your app and the PHP scripts. When the app prepares a request, you hash some of the values that are being sent to the server using your secret method. This hash is being sent with the request. The server does the same and compares the two hashes. When they're the same, it knows the request is from the app (or someone who cracked your algorithm). When they're not, the server can simply ignore the request.
An example:
Data: userid = 2042; name = JohnDoe; email = john-doe#someprovider.com
Hash (in PHP, but you should implement it in the app as well):
<?php
$userid = 2042;
$name = 'JohnDoe'
$email = 'john-doe#someprovider.com';
// Remove some letters with other letters
$name = str_replace(array('a', 'd', 'g'), array('E', 'x', '9'), $name);
// Reverse a string
$email = strrev($email);
// Make a super secret hash (with salt!)
$hash = sha1('fnI87' . $useris . '87bk;s.' . $name . 'unf%gd' . $email);
// Some more fun
$hash = str_rot13($hash);
?>
Request: http://www.your-server.com/script.php?userid=2042&name=JohnDoe&email=john-doe#someprovider.com&hash=YOUR-GENERATED-HASH
Now the server can apply the same hashing method and compare the resulting hash with the hash sent with the request.
I'd like to suggest a more abstract approach, but similar to Jonathan's.
I make the following assumptions:
You have a PHP-script that anyone can call (if they know the URL / sniff the network packets).
Your android app is closed source; meaning that if you have a hash algorithm no-one but you will know what it is.
You want to prevent anyone from directly calling the PHP scripts - circumventing the app and any security you might have built in there.
What you need is way to identify that your app is sending the requests, and not someone else.
The idea is that you generate a signature for each request that only your app can make (ie. a salt + a hash).
$input = array(
"userid" => 1234,
"friendid" => 2345
"etc" => "..."
);
$salt = "s3kr4tsal7"; // this is essentially your app signature
$signature = md5($salt . serialize($input)); // you could also use json_encode or any other to-string serialization
// pick whichever is easy to do in PHP and in your app
$request = array(
"input" => $input,
"signature" => $signature
); // send this
Then in your PHP script check if the signature matches the calculated signature. This is similar to Jonathan's solution but it allows for any input, it's not dependent on $email or any other property. I also don't think you need an overly complex hashing algorithm, just md5 with a salt is 'hard enough'.
There is another type of attack you should be aware of and that is a replay-attack.
If you look at the RAW data going over the line, you could capture it and simply play it again. If you know what action has what output you can simply repeat the output.
The typical solution for a replay-attack is a trial-and-response. SSL does this for you but you could also make a custom implementation (but that is significantly more complex).
As usual, it depends on what level of protection you need, and how much you are willing to invest. Since you cannot use sessions, you need some sort of a stateless way to authenticate. There are generally two ways to do this: post credentials each time (e.g., basic authentication) or send some sort of a token (BTW, the session ID is exactly that, a token that links to a live session on the server).
When you generate the token, it is a good idea to use a standard and proven algorithm, instead of inventing your own and/or relying on obscurity. Even if it looks mostly secure, it might not be. For example, there are known attacks against the MD5 idea above (it is easy to append data to the message without knowing the key and obtain another valid MAC). HMAC-SHA1 is designed to avoid those.
First thing first: if you can, do use SSL for all requests. This would accomplish a few things at the same time:
users (your app) can be sure that they are posting their data to the right place (i.e., your webapp). SSL server authentication takes care of this.
it would make sure any crednetials/tokens you post are automatically encrypted.
replay attack become practically impossible
It seems you already have authenticated users, so issuing tokens should be relatively easy. You might want to think about the protocol to implement, but as you consider more cases, you will be getting closer to re-inventing OAuth and friends. Some things to consider:
an expiration period on tokens: so that even if someone gets a hold of one, they cannot use it indefinitely.
a way to revoke tokens
maybe have different tokens for different parts (services) of the webapp, so you can grant/revoke access to only the necessary services
To make sure you (i.e., your webapp(s)) are the only one that can issue said tokens you would want to sign them with a key only you have. Since the signer and verifier are the same (you) you don't have to use public key cryptography, HMAC should do. You could, for example, concatenate the username, issue time and any other relevant information, and use them as input to HMAC. Pack those parameters along with the signature (HMAC output) to create a token, and have the app send it with each request. Verify on the server and allow access if valid, require re-login (new token) if expired, deny access otherwise.
Alternatively, if you want to authenticate just the app, and not get user info mixed up in this, you could use a similar approach to sign requests on the client (app side). If you choose this way, do use a standard algorithm. This would, of course, require the signing key (in some form) to be in the app, so if someone gets hold of it (by reverse engineering, etc.) they could issue as many requests as they want. There are ways to mitigate this though:
implement the signing logic in native code
don't store the raw key, but derive it at runtime from bits and pieces stored in different places
And of course, the easiest way of all would be to require basic or digest authentication at the server (over SSL, of course), and embed the username and password in the app (sufficiently obfuscated). On the server side that would require only a change in server configuration, a few lines added on the client side. The downside is that there is really no way to change those credentials if they get compromised (short of releasing a new version and blocking access from the old one to force people to update; not pretty).
I want to make nice and clean api; I'm making site and I want to offer the ability to mobile apps use web API of my site.
I don't want to use oAuth, becouse the mobile and embedded applications that are facing the biggest hurdle, as they may not be able to bring up and/or control the web browser. Also its a little complicate.
I know, that HTTP basic authorisation is not safe, but it's so simple... I want to use it in my api.
I have somee users logins and their passwords (md5-encoded) in mysql base, but how to use those data in this HTTP basic authorisation?
Generate a random unique string for each user in your database and make that string available to the end users. When they access the api ask them to enter that unique string that you supplied--this is their 'key'. Each time a users app accesses the api they pass the key which links directly to a unique account and that is how you authorize them. It is essentially user name and password all in one.
While the above example is generic you should also take things like security into account--for example, when possible, pass the device ID from the mobile along and use that during authentication, or use their current password hash during their API key generation so if they change their password the key will stop working and they have to get a new one--this way they can control access if their key is lost.
It doesn't have to be complicated, it just has to be safe. =)
The PHP manual has an example
Jus google your question "PHP HTTP basic" and here you are
http://php.net/manual/en/features.http-auth.php
it is as simple as sending a few HTTP headers.
Also note that digest authorization considered to be more safe but less compatible with clients.
A new project requires a simple panel (page) for admin and staff members that:
Preferably will not use SSL or any digital ceritification stuff, a simple login from via http will just be fine.
has basic authentication which allows only admin to login as admin, and any staff member as of the group "staff". Ideally, the "credentials(username-hashedpassword pair)" will be stored in MySQL.
is simple to configure if there is a package, or the strategy is simple to code.
somewhere (PHP session?) somehow (include a script at the beginning of each page to check user group before doing anything?), it will detect any invalid user attempt to access protected page and redirect him/her to the login form.
while still keeps high quality in security, something I worry about the most.
Frankly I have little knowledge about Internet security, and how modern CMS such as WordPress/Joomla handle this.
I only have one thing in my mind: that I need to use a salt to hash the password (SHA1?) to make sure any hacker who gets the username and password pair across the net cannot use that to log into the system. And that is what the client wants to make sure.
But I am really not sure where to start, any ideas?
The use of HTTPS is an absolute requirement, and must be used for the entire life of the session. Keep in mind that session id's are used to authenticate browsers and if an attacker can obtain one (sniffing or xss), then he doesn't need a username/password. This is laid out by The OWASP Top 10 2010 A3 Broken Authentication and Session Management. If you want to implement secure session you must read that link.
md4,md5 sh0 and sha1 are all a broken message digest functions and can never be used for passwords. Any member of the sha-2 family is a good choice, sha256 is very large and is a great choice for passwords.
You should absolutely never transfer a password hash across the network or spill it to a user/attacker. If you are sending a hash to the server to authenticate then you have introduced a very serious vulnerability into your system. Using sql injection the password hash can be obtained from the database, then this hash can be simply replayed to authenticate, bypassing the need to crack the password hash. This is as if you are storing passwords in clear text.
Use the $_SESSION superglobal and session_start() to maintain your session state, never re-invent the wheal. The default PHP session handler is secure and will do what you need.
session_start();
if(!$_SESSION['logged_in']){
die("Authentication required!");
}
Also make sure to implement CSRF protection into your system. Using CSRF an attacker can access the administrative panel by forcing your browser to send requests. Make sure to test your application for XSS this is a good free xss scanner, again xss can be used to hijack an authenticated session by using XHR or by obtaining the value of document.cookie. It is also a good idea to test for SQL Injection and other vulnerabilities, wapiti will do the trick.
Not using SSL would leave a pretty substantial hole in the whole system as it is pretty easy to sniff network traffic
This has been much discussed on SO already, here are some of the useful links:
Developing a secure PHP login and authentication strategy
Login without HTTPS, how to secure?
Secure Login in PHP