16

I'm currently building an API for a very busy internet website. Its being written in PHP with MySQL. Now this is my first API that i'm writing that allows people to access their account remotely. Once the API is online, developers will be able to write their own tools from it.

Now I have the API working, but I'm not sure if its entirely safe.

An example URL that would work is: http://domain.com/api.php?api_option=list&api_user_name=USERNAME&api_user_password=PASSWORD

USERNAME: would be the users actual username

PASSWORD: would be the MD5 encoded string of their actual password.

If the details match, a result is returned, if not, and error.

All external $_GET inputs get the mysql_real_escape_string() treatment.

I wanted to keep things simple, but I'm not sure if this way is a SAFE way of having a public API that taps directly into users accounts data.

Ideas and suggestions are much appreciated.

Veve
  • 6,643
  • 5
  • 39
  • 58
Mr.Boon
  • 2,024
  • 7
  • 35
  • 48
  • having a hash of a password in a URL isn't a great idea. A better way may be to have an API key - which invokes some form of authentication, between the user and the API. – diagonalbatman Feb 04 '11 at 17:25
  • Thank for all the comments, OAuth, seems a bit complex for what I need, so I'm building my own API key setup. I have something working where an auth key gets stored in the database with the user_id linked to it. This setup works, but users still need to obtain this key, and if others build tools from this API, users need to be able to login with their username/pass that they registered with. So I still don't see how to get round an initial $_GET url that can receive both the username and password to generate the API key remotely. – Mr.Boon Feb 04 '11 at 18:55
  • Suggestion : 1. At least use HyperText Transfer Protocol Secure (HTTPS) and not HTTP. 2. Send the logins via POST (not via URL/GET, as they will appear in logs) – zeuf May 24 '19 at 11:35

4 Answers4

18

Please, for the love of the Internet, DO NOT DO THIS. I implore you to put the time into implementing OAuth for your API. Please. Please please please.

Take a look at this: http://toys.lerdorf.com/archives/55-Writing-an-OAuth-Provider-Service.html

Spencer Hakim
  • 1,543
  • 9
  • 19
  • 1
    Do you really have to use OAuth? I don't like it...(although I agree that the above method is not good/safe) – o1iver Feb 04 '11 at 17:32
  • @o1iver: I'm recommending OAuth just because it's fairly ubiquitous and plenty has been written about it, especially since the OP clearly can't be trusted to come up with his own security implementation. Any token-based authorization system would be better than what he's currently doing, though. – Spencer Hakim Feb 04 '11 at 17:37
  • ok, I agree with you about token-based auth, I just don't like OAuth :-) – o1iver Feb 04 '11 at 17:41
  • @o1iver: That's fine, haha. Feel free to add your own recommendation for a token-auth system, I'm curious as to what other people use (I've only ever had the pleasure of using OAuth and OAuth derivatives). – Spencer Hakim Feb 04 '11 at 17:43
  • I am currently working on something after finding that I don't like OAuth. But I am just trying different things at the moment...so can't really contribute much :-) – o1iver Feb 04 '11 at 17:50
10

Do not use a password for API clearance, even if it is encoded, especially if it is encoded in MD5. Furthermore I would not use the users username as well. Let the user generate a key. You are giving someone the ability to know 50% of what they need to know to access a user's account, and MD5 has a lot of sites that you can reverse it and find a password match. A key is certainly the best way to go so a developer could regenerate it further down the road for security purposes. Always think of security.

Darren
  • 10,631
  • 8
  • 42
  • 64
9

How about signing requests using HMAC_SHA1 and the user's password? For example, your URL: http://domain.com/api.php?api_option=list&api_user_name=USERNAME&api_user_password=PASSWORD

Add the timestamp and/or a random string (nonce) and build a normalized base_string:

$base_string = "api_option=list&api_user_name=USERNAME&timestamp=1296875073&nonce=hgg65JHFj";
$signature = hmac_sha1($base_string, PASSWORD);

then the new URL would be: http://domain.com/api.php?api_option=list&api_user_name=USERNAME&timestamp=1296875073&nonce=hgg65JHFj&signature=kfvyhgfytgyr6576yfgu

What your server does is to get all the options, excluding the signature, then generate the signature using the same method and compare it to the signature sent by the client, which should be the same.

Arvin
  • 2,272
  • 14
  • 10
  • Hey Arvin, thanks for the response. I'm starting to get the general idea. Can you please comment on the following setup. 1. webmasters sign up for use of unique webmaster_api_key 2. $_POST requests can be made to apilogin.php only via https which include 'username','password','webmaster_api_key','timestamp'. 3. apilogin.php would run $base_string = "username+timestamp+webmaster_api_key"; $signature = hash_hmac('sha512', $base_string, $password); and return $signature, if login details where valid. This $signature is logged in a sessions database, with the user_id linked to it. – Mr.Boon Feb 05 '11 at 09:42
  • Also, i am not 100% sure how to go about expiring times of sessions. I guess users want to stay logged in for a longtime in certain scenarios. Also, users might want to stay logged in using various tools, which would mean various sessions stored in the db for just 1 users. What would make a session expire, apart from someone clicking logout? – Mr.Boon Feb 05 '11 at 09:46
0

first of all, You don't need to send the user's login credentials using the GET method. You probably want to do that using the POST method so it can be hidden from the url.

then in your api backend, You can get it like this

$username = $_POST['username'];
$password = $_POST['password'];

Still though, what you've done so far is not any guarantee that you API is safe .

In order to provide a much more safer method, You probably want to assign AUTHENTICATION TOKEN to each user .

PS: dont know if this helps anyone lol