Settings

Theme

How not to write an API

ghost.teario.com

407 points by gebe 12 years ago · 171 comments

Reader

Mithaldu 12 years ago

Short version: http://criticker.com sells access to their API for apps. Any API account can retrieve a list of all users it registered on the site, then retrieve the cleartext password for each user it created.

There are so many WTFs in this whole situation that it's a wonder criticker has managed to keep the website online. Which is a shame, as it looks like a really useful website.

  • theboss 12 years ago

    I dont think you realize how common the WTFs in this situation are. If you are dealing with a reputable company, this is super super WTF.

    When you are looking at a small website/API someone made for fun or something....It can normally be badly broken in less than 2-3 minutes....and I'm not even that talented like some of the guys out there.

    • lbarrow 12 years ago

      Security is definitely hard, but security challenges are often proportional to your apps' surface area. If you just have a simple token-based API, your language probably has libraries that can get you started with a reasonably designed security story. It's the same with passwords: at this point, you shouldn't be rolling your own password management system unless you have very specific needs.

      For this reason, I don't think "I made it for fun" or "I made it over a weekend" is a good excuse for such broken security. For tiny new apps, it's easier to use a library that does it correctly than it is to roll your own.

    • Mithaldu 12 years ago

      My day job is web developer and i sit in an IRC channel where roughly half the traffic is making fun of security issues of sites. Such a glorious combination of fuckups doesn't come about that often. I'm honestly more apalled that the passwords are in plaintext than that they expose them like that.

      I cannot say i am surprised though. A general amount of carelessness, undeserved self-confidence and ignorance is a given in most websites, especially when it comes to PHP.

      • theboss 12 years ago

        I'm not sure I agree with ``carelessness, undeserved self-confidence'' but I definitely agree with ignorance.

        I think the best thing is that people writing code just don't understand the internals of how a lot of web attacks work and why the best practices for security prevent them.

        I reported two account hijack vulnerabilities on startups this weekend and was met with ``What is CSRF?''.

        I think the reason for this is security people keep to themselves and work as consultants. Instead of making my own company, I can go around finding people who need what I know and get easy low-risk money.

        Also, there really is no place to hire a ``security person'' at a early stage startup. If a security guy DOES get hired, it's either part of an IR team, an internal pentest team, and if this is the case then there's already way too much code written to even check it for the most basic best practices (you might use some tool for static analysis but are you really going to check out the thousands of issues?)

        I don't like bashing PHP, because I think it is actually a phenomenal language for people who know what they are doing, but it is definitely a security death-trap for those who don't.

        • mgkimsal 12 years ago

          "I think the reason for this is security people keep to themselves and work as consultants."

          ???

          I know there are some pretty obscure edge cases in some successful attacks, but... almost everything I see as a security issue (and stuff I've done myself) usually falls in to XSS, CSRF and SQL injection. Those were the big 3 10+ years ago, and probably still will be. This isn't some magical 'hidden' info that a handful of security consultants hoard to themselves to maximize top dollar.

          Have safe password/authentication systems, prevent XSS, prevent CSRF and prevent SQL injection - you'd prevent a HUGE number of attacks for little effort. But... it takes education, and actually caring some about your job/company/product.

          "Also, there really is no place to hire a ``security person'' at a early stage startup. " Why not? I don't think they need 'hiring' full time. Many startups spend inordinate amount of time on 'user experience' and 'branding' and whatnot, with the (correct) understanding that you can't easily just 'add on' UX after the fact - it's much easier to develop UX as part of the overall dev process. Why do people not think of security the same way? Regular security audits/reviews by a security consultant (1-3 hours every week or so) would go a long way towards helping inexperienced developers spot gaping/obvious security holes well before they become big problems.

        • Killswitch 12 years ago

          > I don't like bashing PHP, because I think it is actually a phenomenal language for people who know what they are doing, but it is definitely a security death-trap for those who don't.

          Any language is a security death-trap for those who don't know what they're doing.

        • raesene3 12 years ago

          If you're worried about not being able to get access to "security people", I'd recommend looking at OWASP (http://www.owasp.org) which has a lot of good free information and also chapter meet-ups which are free.

          Interestingly one of the problems I've faced running an OWASP chapter is how to get more developers along to it.

          Also security.stackexchange.com can be quite useful

        • camus2 12 years ago

          @Killswitch

          Problem is PHP is a templating language, not a generic purpose one. Other languages use frameworks for webdevs that usually provide basic security features like auto escaping output,orms by default(so no sql strings),csrf on forms...

          PHP doesnt ,so it's easier to shoot yourself in the foot.

          • mikegirouard 12 years ago

            You've almost got a point there except PHP has quite a few frameworks to choose from. Mainstream ones all include, as you put it, "basic security features like auto escaping output,orms by default(so no sql strings),csrf on forms".

            Symfony2's form component is one of the best I've ever seen. It has many sane defaults and is locked down out of the box. Read up on their use of data transformers and how they protect users against XSS without any extra effort by the user. Validating automatically looks for a CSRF token.

            Whats more is that these are (for the most part) stand-alone components. You don't need to commit entirely to the full Symfony stack - you can just opt into using the components you need -- even the smallest project that only uses PHP as a "templating language".

          • jimlei 12 years ago

            You mean like Symfony, Laravel, etc? Frameworks that a lot of PHP developers use these days...

            • camus2 12 years ago

              You dont need a framework to do PHP webdev, in every other languages,you do.That's my point, PHP IS a templating language,no Symfony,Zend or Laravel can change that. If i write "print" in Python it wont output the result back to HTTP like PHP does. Ruby or Java dont have <?ruby or <?java tags, you get my point.

              • smacktoward 12 years ago

                > Ruby or Java dont have <?ruby or <?java tags

                I dunno about Ruby, but Java certainly does: http://en.wikipedia.org/wiki/JavaServer_Pages

              • core1024 12 years ago

                With PHP, unlike other languages, you have not two but three options - you can either run it as a web server module (That's your "templating" opinion and the most common use of PHP), you can run it trough the Common Gateway Interface (where even in Python or Ruby print DOES outputs to the HTTP) and in the end you can roll out your own HTTP server. In the last option, just like the common use of Python and Ruby, you have full control of what's going on with your code and you decide what to send over the socket and what (if anything) to print on the console.

              • mschuster91 12 years ago

                If you use them in CGI mode, you very well have a "start" tag in form of a shebang first line like #!/usr/bin/env python.

                Also, shellscripts and perl are considered programming languages, and these too need a shebang line. Your point is invalid.

              • pushrax 12 years ago

                Well, many Ruby webapps use erb, which is basically the same thing.

      • woah 12 years ago

        What channel is that? As an app developer, it sounds useful.

    • corwinstephen 12 years ago

      Rails + Devise = answer to all these problems.

  • euank 12 years ago

    I think you got a detail wrong.

    I think that the app can only access all users registered with its api key. Same for passwords.

    You say "all users registered on the site", the api says "Note, this can't be used to lookup just any user's password – the user must have been created by the API account."

    • matthewmacleod 12 years ago

      However, the API key for any app can be discovered with zero effort, because it's included in each request. So you can retrieve the plaintext passwords for any user who has signed up with any app using the API.

      Whoever created this monstrosity should be ashamed of themselves.

      • rmc 12 years ago

        To reiterate: Any user of an app can look at the passwords of any user created with that app.

    • Mithaldu 12 years ago

      Dammit, thanks, i corrected that.

  • icebraining 12 years ago

    As a user, I can say it is a useful site, and the score prediction engine is very accurate, in my experience. Shame about this, it's truly a security clusterfuck.

  • elwell 12 years ago

      Due to a security breach, the Criticker APIs have been taken off-line for an unspecified amount of time.
    
      We apologize for the inconvenience.
    
    
    [0] - http://api.criticker.com/
  • sauerbraten 12 years ago

    Correction: an API account can see all users that registered through the API with that account's key.

    Still, WTF!?

damon_c 12 years ago

Whenever I get that plaintext password "vibe" on a site, I like to make my password something somewhat degrading go the site; like "thisSiteSux!", but slightly more vulgar. It's not my fault if they see it.

Once after having gotten the vibe, I ended up on phone support with the site in question. At some point I was instructed to "log back in with ummmm that uhhh same password you signed up with...." I could tell that my plaintext-dar hadn't failed me that time :)

Osiris 12 years ago

Could someone with a solid security background provide a example of how to properly handle the issues that this API fails so badly at?

While some developers may be able to clearly identify bad practices, best practices may not always be so clear.

I'd love to know what a best practice would be for things like authentication to an API and some of the other issues brought up here.

  • JangoSteve 12 years ago

    I wouldn't say I have a solid security background, but there are four best-practices I can think of that would have prevented the security vulnerabilities outlined by this post:

    1. Hash the secret API token/key given to each client that is sent to the server with each API request. This will prevent attackers from being able to find out your secret token.

    If you only hash the secret token though, this still won't help, as attackers could just send other API requests along with the hashed token. Instead, you will want the client to hash other data unique to the specific API request as well. For example:

        http://api.example.com/api_function_name?app_id=my_app&hash={hash_value}&other=stuff
    
    Where the hash_value is computed by the client with something like:

    EDIT: Clarified hash_function parameters, thanks @eru.

        hash_function( secret_key, api_function_name)
    
    The API server will then receive the request, look up the client's secret_key based on the app_id, and run the same hash_function to make sure it matches hash_value in the request.

    This would mean attackers couldn't reuse the hashed value to send other API calls. But they'd still be able to send calls to that function and just change the parameters to the call to get other information from that API call. So, you could also include the other API call parameters in the hash_function as well, which would mean attackers could only replay that exact API call and not change any of the parameters.

    You might notice, this is still not good. So, to prevent this "replay attack", you would also generally include the current datetime in the API call as well:

        hash_function( secret_key, api_function_name, datetime )
    
    Now, attackers can't even replay the exact request, because by the time they do, the datetime will have changed and so the API server would reject the request if it was replayed later. And since the attacker still doesn't know the unhashed secret_key (since it's never been transmitted in plain text), they can't change the datetime without invalidating the hash_value.

    This is theoretical though, because in reality the above wouldn't work well if the clocks on the client and server were at all out of sync (and they probably will be). So, usually, you'd also have to include the current datetime of the request as another parameter in the call to let the server know exactly what datetimestamp was used in the hash_function, and the server will simply make sure the datetime is within an acceptable window of the current datetime on the server. Of course, the bigger the window, the easier to get the API working with clients, but the larger the window for allowing replay attacks.

        http://api.example.com/api_function_name?app_id=my_app&hash={hash_value}&other=stuff&time=datetime
    
    And lastly, the chosen hash_function for the API should be something not easy to brute-force (meaning don't make it easy for attackers to listen to a few API calls and be able to reverse-engineer the secret_key, since they'll already know what hash_function is from the API documentation).

    OK, 1 was longer than I anticipated, but the others are pretty short.

    2. Another more full-proof way to prevent attackers from getting secret tokens, hashed or unhashed, would be to make all API requests work only via HTTPS.

    3. Don't provide API (or any) access to user passwords.

    4. Don't store user passwords in plain-text, or even via simple hashes. Instead use a cryptographically secure hashing function with salts.

    • Rizz 12 years ago

      Sorry for being harsh, but your "solutions" are mostly useless in the context of providing an API for phone apps.

      Use OAuth or similar and make sure every user has their own account. That's the only answer. Don't roll your own! Especially don't roll your own when you don't have a solid security background. You have obviously heard some of the right terms, but how and where you can apply them is at least as important as using them at all.

      1. Doesn't protect anything at all. Hash functions don't do anything when people have access to the program code. No matter how fancy you go with time limited hashes (and there are smarter ways to create those). At most it adds a few minutes to the reverse engineering.

      2. Again, this doesn't protect against anything. HTTPS stops intercepts on the wire, not someone who has access to your app, people can still lift the secret keys and the hashing scheme from the app binary.

      3.& 4. Both true, and would protect against mass stealing of the passwords like happened here, but it wouldn't prevent abuse of the API.

      There are very many people who use techniques like the ones you suggest in 1. and 2. and the same very many people have vulnerable apps that usually expose all users' data to the world. There are a lot of apps that store e.g. user files or some sort of configuration not on a per user OAuth protected storage like OneDrive, DropBox or Google Drive, but either there but on just the account of the developer, or on another storage that is only authenticated with the developer's credentials. People who do that allow anyone to read and modify the data of all users, exactly the same as people are allowed to do to their own data, or more if the credentials aren't properly limited, even if it's blocked in the app.

      • JangoSteve 12 years ago

        When it comes to API security, you can't be too harsh! I guess I was trying to explain it more conceptually, since it sounded like the person asking didn't understand the concepts.

        But I stopped short on #1, as your post points out. You're absolutely right when it comes to designing an API for consumption by apps that will be distributed as packages.

        I can't update my original post with a clarification, so here's what the end of #1 should have said:

        1 (continued)

        If either the clients' source or compiled code can be inspected by attackers (which is true for distributed, i.e. native mobile or desktop, apps), you don't want to make client app developers include their secret authentication key directly in their app. In this case, consider using OAuth 2.0 for authentication instead.

        With OAuth, the client app has the user authenticate with their own credentials, where the API will respond with a per-user access token (that can easily be revoked per user if necessary), which the client app will then use for subsequent authorized requests.

    • eru 12 years ago

      You can also include an extra random number in the hash, and require that within the window of acceptable timestamps the random numbers have to be unique.

      By the way, be aware than hash(string1 + string2) constructions are often vulnerable. hash(hash(string1) + string2) is better for most hashes, I believe. But you shouldn't roll these primitives yourself, either. Just use a proper library.

      • JangoSteve 12 years ago

        You're absolutely right about the hash constructors. I was trying to make it clear what's happening conceptually, but that's why I included the note to choose a cryptographically secure hashing function. HMAC is generally a good hash constructor pattern to use.

        EDIT: Just realized it'd probably be clearer to replace the pluses with commas in my examples, to avoid implying the relation between the parameters of the hash_function.

           hash_function( secret_key, api_function_name, datetime )
      • Genmutant 12 years ago

        Do you have specifics on why strcat would be vulnerable? Or is it just because "abc"+"def" == "abcd" + "ef"?

      • stouset 12 years ago

        HMAC.

    • jrub 12 years ago

      I think you're describing an HMAC[1] authentication code here.

      Certainly signing your requests as actually having come from your application is a legitimate means of security. But there are much lower hanging fruit (in terms of available security measures). Specifically, using SSL to handle API traffic. That should absolutely always be step 0. In instance of this specific post, had the API provider enforced using SSL as their transport protocol we probably wouldn't even be having this discussion.

      There's a ton of other security measures/protocols that should be taken and followed, most of which are already talked about in other parts of these comment threads. I just wanted to really point out that what you're describing above sounds an awful lot like an HMAC code.

      [1] http://en.wikipedia.org/wiki/Hash-based_message_authenticati...

      • JangoSteve 12 years ago

        You're correct; if you see my reply here [1], you'll notice I mentioned it by name.

        See #2 in my original response concerning SSL. And notice the difference in length and complexity between #2 and #1; it was written this way intentionally to highlight the complexity of doing security authentication properly, in order to encourage the use of SSL, given that it is both more "full-proof" and simpler.

        [1] https://news.ycombinator.com/item?id=7371259

        EDIT: Please also see the point @Rizz pointed out, in that you'd still want to use something like OAuth, since HTTPS doesn't solve the issue of an attacker knowing your client's API key by inspecting its distributed code.

    • aptwebapps 12 years ago

      I think your efforts on #1 are moot because I don't think there's a way to include the API key in a mobile app such that it can be used by the app but not extracted by an attacker.

      • misterjangles 12 years ago

        #1 is a fairly standard security concept used by protocols like oAuth or JWT. It requires an API key pair (public and secret key).

        The secret key is only used for signing and is never passed in the request. Used in combination with nonces and time stamps you can make a secure API that isn't susceptible to replay attacks.

        • thedufer 12 years ago

          Doesn't https take care of the same issue, though? And it doesn't solve the problem that if you're shipping an app the secret key can be found. So what does it solve?

          • misterjangles 12 years ago

            You're correct - you shouldn't ship an app with a secret key embedded. That would be a flawed implementation.

            It's hard to be specific without knowing what you're doing. If you have an app that connects to a third party API like Twitter, that's one situation. If you have an API that other app developers will connect to - that's a second scenario. And third is if you have an API and you write your own app to connect to it.

            OAuth handles all three of these scenarios but in #1 you are a consumer, in #2 you are a provider and #3 you are both.

            Check out 3-legged oAuth for an example of how to allow apps to talk to your API on behalf of a user, without that user having to give their password to the app. It's actually pretty interesting, clever and simple all at once!

            HTTPS encrypts the traffic - making it difficult to sniff. It doesn't actually provide authentication though.

            • dawkins 12 years ago

              Even if your api uses oAuth I don't see how can you prevent the client app to steal the password. At some point the user is going to have to give his password to someone. Can't the app ask the user for his password, keep it, and internally give it to oAuth to allow to use your api?

              • mmcnickle 12 years ago

                The user will enter their password on the provider's site via the phone browser. It relies on the user's trust of the system browser.

                • dawkins 12 years ago

                  I meant for a native app and you being the provider. If you don't trust the client app even oAuth won't help you preventing the client app to know the user password.

                  • misterjangles 12 years ago

                    It is true you have to trust that the native app is not tricking you into thinking that you're entering your password on Facebook.

                    But, at least if it's implemented correctly and not maliciously, the app doesn't ever see your password.

        • Kiro 12 years ago

          Even if it's not passed in the request it's still in the app so isn't it vulnerable to reverse-engineering?

          • misterjangles 12 years ago

            There shouldn't be a key baked into the app. Each user gets their own unique key. so the worst you could do reverse engineering the app is to steal your own key. There should never be any "master" key used for all users.

    • woah 12 years ago

      What's the advantage of using your hand-rolled hashing scheme instead of just https?

      • JangoSteve 12 years ago

        There's not really any advantage as far as I know. In fact, as I stated in my explanation, using HTTPS is more full-proof. So why wouldn't you do that instead?! That's the point.

        If I had to think of an advantage though, it'd be for the sake of any developer who needs to design their first API, and is inspired by yours. If you just used #2 then with plain-text authentication, and a developer copies your API without using SSL, then they'll have a horrible security problem. If you used #1 as well, then they'll still have an okay API, it just won't be suitable for use by packaged/distributed client apps.

        In fact, this is purely conjecture, but that could be what happened here in the case of criticker. Who knows?

      • rblatz 12 years ago

        You could just run fiddler on windows and trust the fiddler certificate. This would allow it to MITM the https session.

  • fauigerzigerk 12 years ago

    First of all you need to make a decision. Do you require your users to entrust the client software with their passwords or not.

    If you can do that, the solution is pretty simple. Do it as you would do it with any website. Simply use https (TLS) to transmit username and password and return a session cookie to use in subsequent requests. Run your API over https only.

    If you don't want your users to entrust client software (i.e. apps) with their passwords then use https with OAuth.

    The reason why using https alone works well for web apps is that users can trust their browsers. Browsers can know the password and they probably won't steal it.

    However, if you provide an API and you expect many different client apps, including some dubious ones, to use that API on behalf of your users then users cannot trust the client software and hence you should use OAuth.

    The decision doesn't depend on whether or not your application stores sensitive data, because users often use the same password for different sites. So if you like your users and you provide an API for mobile apps to use, you should use OAuth.

  • balls187 12 years ago

    Usually with an APIkey, you have a corresponding "Secret" Key.

    This is called a shared secret.

    Using the shared secret, you can come up with a unique signature, that only yourself and the host can generate.

    You also want to use some sort of TTL for the signature, to prevent replay attacks.

    Passwords should never be stored in plaintext. They should be hashed using a cryptographically secure hashing function (bcrypt is easy enough).

    Password hashes shouldn't ever be exposed to anyone.

    If you need to provide login functionality, provide a method that takes a username and password.

    Make sure that username and password method has a backoff time to prevent someone from partying on that api (calling it with username and password combinations)

    As the password has to be sent in clear text, make sure your login api is over SSL.

  • cjfont 12 years ago

    When I have a simple app send a password to the server, I like to generate a hash on the client side and then rehash again on the server for storing.

    As far as APIs, the good ones will hash your secret key together along with other data unique to your HTTP request, in particular the headers and the datetime. This is a good idea because: 1. you are not sending your secret key in clear text 2. it makes it difficult for a man-in-the-middle attack because they cannot just take your hash from one of your requests since it will be invalid after received or if some time has elapsed.

    For an example, see how Knox sets up requests for Amazon AWS: https://github.com/LearnBoost/knox

    • viraptor 12 years ago

      > I like to generate a hash on the client side

      I'm confused. What do you do with that hash then?

      • cjfont 12 years ago

        It is sent to the server, instead of the clear-text password. This isn't really necessary if you're using HTTPS, however.

        • duskwuff 12 years ago

          Sending a straight hash of the password is no more secure than sending the password in cleartext - an attacker can just replay the hash they sniffed off the network.

          As skyebook said, use HTTPS. There's no excuse.

          • cjfont 12 years ago

            This practice is more to prevent the user's password from being revealed than it is to prevent others from logging in as you. In a trusted environment, you may not care that someone there has access to your account, but you don't want them to know what password you chose.

            Having said that, do use HTTPS when possible, but keep in mind some corporate environments force proxies that can see your traffic anyway.

          • icambron 12 years ago

            I agree there's no excuse not to use (and force) HTTPS, but the parent did say:

            > hash your secret key together along with other data unique to your HTTP request, in particular the headers and the datetime

            So that isn't a straight hash and you can't just trivially replay. It does require you store the secret in the clear (or at least reversibly) on the server, but I see a lot of APIs do that...

        • skyebook 12 years ago

          For anyone reading: please just use HTTPS!

  • misterjangles 12 years ago

    Using a standard library for authentication like oAuth or similar is generally a better idea than creating your own. It's also usually easier since you don't have to re-invent the wheel.

    Aside from that, I don't see a reason for an API to be able to retrieve passwords. If passwords need to be reset then the API could maybe issue a pass reset request that would email a confirmation link.

    The plain text password is something that's beyond the API design, but a one way hash is generally better with an algorithm that is recognized as being secure (not MD5).

    Basically, to repeat, simply not designing your own security but using recognized libraries will typically be a better idea.

mercurial 12 years ago

Somebody is trying to outshine Mt. Gox in terms of amateurism. I wouldn't be surprised to find a number of other vulnerabilities (SQL injection ?). Who the hell thinks it's OK to store non-encrypted passwords in this day and age? It's not like you don't have a major security breach every month...

Also, I like the 'handler.php' endpoint returning some kind of ugly pseudo-SOAP. Ugh.

  • scoot 12 years ago

    "Who the hell thinks it's OK to store non-encrypted passwords in this day and age?" You'd be surprised: http://plaintextoffenders.com/

    ...and an amazing number of finance organisations who can't handle non alpha-numeric characters in passwords, indicating failure to hash.

    • stevetjoa 12 years ago

      I was a reviewer for a Springer journal (MMIR). I contacted Springer in October 2012 to let them know that they store plaintext passwords and share the plaintext passwords with their users (e.g. "Hey, it's review season again. Please login to accept or decline your review assignments. By the way, if you don't remember your password, here it is! abc12345"). Over a brief email exchange, I carefully, politely, and concisely laid out the problems with doing so. All I got was a hilariously dismissive reply.

      In October 2013, I received another email from Springer with my password in plaintext, and they CCed this email to another person!!

      I declined my review assignments, asked them to permanently delete my account, and I haven't heard from them since.

    • martypitt 12 years ago

      I was astonished to discover about 18mths ago that MelbourneIT, Australia's largest Domain Registrar stores their users passwords in plain text, and display them to the customer service reps during calls.

      I discovered this when on a phone call, the agent asked me what my password was, and when I refused to tell him (but offered any other aspect of my account for identity), it took a lot of convincing to get the rep to serve me. If I were malicious, I could speculate that a little social engineering may have gotten the employee to give me the password.

      EDIT : To clarify, it was a comment the rep made about my password indicated that he could see my password in clear text on his screen. I asked him, and he confirmed this.

      I tweeted the CTO [1], who advised me they were working on the problem, but it was still several months away from being resolved.

      This level of insecurity from a major IT service provider was both shocking, and inexcusable in my humble opinion.

      [1] https://twitter.com/marty_pitt/status/223622794490019843

    • mschuster91 12 years ago

      Or they want to avoid the problems that can arise with multiple systems having to authenticate at the system - some of which might use non-exchangeable ways of encoding stuff like Umlauts.

      Or they want to avoid the customer service calls "I am in Russia and use a Euro sign in my password, how do I login?!?!?!"/"Help, I have a Macbook from my brother, where is the vertical pipe (|) symbol?" so they restrict the keyspace to azAZ09 for reducing this type of error.

      • mschuster91 12 years ago

        Self-reply, as the edit window is out of order: don't forget mobile devices (the support of software IMEs for anything outside the alphanumeric range is spotty to say the best), and as you're talking about financial institutions, also think about ATMs and PoS terminals where the only thing you have worldwide available is a 0-9 keyboard.

    • m_darkTemplar 12 years ago

      Many of these are the sites sending users generated passwords which doesn't necessarily indicate that the passwords are stored in the database as plain text. It's reasonable that the passwords are generated, the email is sent with the password, then the password is hashed and stored in the database, and the plain text version deleted.

    • jcromartie 12 years ago

      > finance organisations who can't handle non alpha-numeric characters in passwords, indicating failure to hash

      When I see this kind of limitation, I usually assume that they have some old mainframe with a fixed-width 7-bit password field, that would take an enormous engineering effort to change or replace.

  • leobelle 12 years ago

    > Who the hell thinks it's OK to store non-encrypted passwords in this day and age?

    The post gave no indication how Cricketer was storing the passwords. They may very well be stored encrypted.

    You can send plain text passwords back if you've encrypted them, you just have to decrypt them first. There's no point at all in returning the results of encrypting a password if the clients don't know how to decrypt those results. Given that the API uses plain text HTTP, I doubt that the passwords are encrypted.

    What the passwords are not stored as however, are hashes. A hash is not the same as text that was encrypted. A hash is a difficult to reverse unique identifier for bit of text.

    Having said all this, it is funny to see your post, and all its replies making fun of security incompetency while also being incompetent in themselves.

    • eru 12 years ago

      > You can send plain text passwords back if you've encrypted them, you just have to decrypt them first.

      Yes, and security-wise that's just a slightly obfuscated version of plain text.

      • leobelle 12 years ago

        That's not true at all. If you use secure encryption to store plain text, and proper use of HTTPs to transfer said text, that's secure. It's not as bad as obfuscated text. What you've said is just plain untrue.

        One problem with storing passwords is that there is no good reason to. The other security issue is that people reuse passwords. So everyone should be creating hashes instead of encrypting passwords, but encrypting text, and transmitting it securely is still secure. This API didn't do that, it did a lot of things wrong, but these comments are all pretty ignorant as well.

        It's just one inane comment after another in this thread.

        • peq 12 years ago

          It is secure against man in the middle attacks, but still if the password database is leaked, then the pain text passwords are most likely also leaked and you have to tell your users to change their password everywhere where they have used the same or a similar password.

  • minimaxir 12 years ago

    Non-encrypted passwords are an artifact of legacy systems, and some modern businesses believe that the risk of plain-text passwords being leaked is lower than the risk of systems breaking due to updating passwords/authentication to an encrypted schema.

    Some modern businesses don't make the best decisions.

    • wldlyinaccurate 12 years ago

      No, non-encrypted passwords are an artefact of poor design and incompetent programmers. Cryptographic hashing has been around since the 70's, and cryptography itself pre-dates history.

      There is no excuse --no excuse-- for storing passwords in plain text. Anybody who attempts to justify it deserves a swift thwack in the back of the head.

    • mercurial 12 years ago

      > Non-encrypted passwords are an artifact of legacy systems

      The copyright is from 2004, that's only 10 years ago. I wouldn't say plaintext passwords were a sensible decision back then.

      > Some modern businesses don't make the best decisions.

      Some modern businesses don't have the best priorities.

  • SideburnsOfDoom 12 years ago

    I am surprised that this is the only comment mentioning SOAP.

    I know that it'a a footnote to the insane brokenness of the rest of it, but ugh indeed. Anyone who remembered SOAP the first time around wouldn't re-invent it badly. Or at all.

PythonicAlpha 12 years ago

It seems to me, that many companies think, that computer science is just plainly simple. You can just put any task to a new bachelor or even student that claims he can program.

I learned the hard way, that even the creation of internal APIs of software is hard, since you can make many errors. I made many errors, after I came from university. After I made them, I knew it better, because I had to manage an other developer that had to use it and I saw what a mess it was.

External APIs are even more difficult to create, because such things as security and others have to be covered ... but still it seems many companies thing any stuff scribbled by a student in the first semester would suffice.

_dztf 12 years ago

I don't care if this comes off as trolling, but here it is: as I read through this, I thought to myself, much like the author, "how appaling!" - then I saw the word "PHP" - and went "oh, well, that figures".

  • Killswitch 12 years ago

    I don't care if this comes off as trolling, but here it is: as I read through this, I thought to myself, much like the author, "how appaling!" - then I saw the word "PHP" - and went "oh, well that means there's gonna be a bunch of people hating on a language because one developer doesn't know what he's doing and happens to be using that language".

    • hamburglar 12 years ago

      All the php hate I've seen over the years is because of one guy who doesn't know what he's doing? ;)

      • Killswitch 12 years ago

        Oh yeah, I forgot, because of the low barrier of entry, PHP is the only language in the history of all programming languages where there are people who don't know what they are doing. Forgot that all Python, Ruby, etc devs are gods gift to programming and don't make mistakes. My good, your bad.

        • hamburglar 12 years ago

          upvoting you despite your inability to take a bit of good-natured ribbing

          • Killswitch 12 years ago

            Sorry, just as a PHP developer who understands his language isn't perfect but is growing and fixing pains, it annoys me to see people who don't use or haven't used the language since PHP4 talk trash about it as if they've been a PHP developer for years and use it daily.

            Rarely do you see PHP developers talking about the pitfalls of big frameworks and other languages.. For example XSS vulnerabilities that recently plagued Rails.

            I too have upvoted both your replies to show no ill will. Beautiful day here in Chicago and I took a little time off to cruise the city before coming back and getting back to work. Really puts you in a good mood.

            • hamburglar 12 years ago

              PHP's public image problem is mostly due to the direction from which you can approach it. You can be the maintainer of a static HTML page who knows nothing at all about programming, and someone can help you dip your toe into PHP by showing you some simple tricks, and suddenly you have the ability to start adding code here and there, copy/paste style, to your content. The results are predictable. And for better or for worse, the language has been given some ill-advised features in order to cater to this type of user.

              And you can approach it in the opposite direction, as well: as a programmer who knows what he's doing, you need to choose a language and a platform to run your app on, and PHP is ubiquitous and perfectly capable, and you know which ill-advised language features to avoid, so it's a reasonable choice.

              The difference between PHP and most other languages for building web sites is that with most other languages, you simply can't follow the first path. Web servers that let you just drop snippets of ruby into HTML are not everywhere (I assume that exists in some ill-advised apache module, but I haven't personally seen it). You need to know a significant amount up front to get your code running, so the "never even considered programming before" portion of the population is naturally suppressed. It doesn't mean they don't exist or that somehow making a language more difficult to use automatically makes its users better, it just means that a certain type of amateur user is naturally suppressed, so there is proportionally fewer of them.

              Note the similarities: ActionScript/Flash is actually a pretty cool piece of technology [let's ignore their poor track record with regard to security holes in the runtime, since that's an orthogonal issue]. And yet it's terrible to program in for a seasoned developer because the community is so chock full of artists and amateurs who just dipped their toe in to add some minimal interactivity to their drawings that you often have a hard time finding docs that are written above the copy/paster level. And well-written ActionScript code is a relative rarity as a result. I'm sure that on at least some level, any seasoned dev who primarily uses PHP can relate.

              • Killswitch 12 years ago

                > The difference between PHP and most other languages for building web sites is that with most other languages, you simply can't follow the first path.

                I agree, but funnily enough, I started at the first path, and if it wasn't for that path in 2001, I wouldn't have made it to the second path.

      • krapp 12 years ago

        ...Rasmus Lerdorf?

minimaxir 12 years ago

<RequestProcessingTime>-0.036264</RequestProcessingTime>

Wait, did their API return a negative processing time?

d64f396930663ee 12 years ago

It's a felony in the US to do what the author did here, right? Not that there's any indication where they're from, I'm just curious.

  • feralmoan 12 years ago

    I'm going to say FU to the industry and buy a horse ranch if it is! These were all public documented endpoints and 'worked as intended'. criticker is next-level incompetence, that's pretty much the point.

    • jamestnz 12 years ago

      Well saddle-up, my friend ;-)

      In seriousness, recall the weev/AT&T case[1]. As I understand it, the attack was roughly of the sophistication of making a totally unauthenticated request to:

      get_user_email_address.php?id=N

      (where N was from a series of sequential integers)... and apparently the feds had a colorable argument that N constituted an "access control system", and therefore the act of iterating the entire series of possible N values (and downloading the resulting data) constituted "unauthorized access to a protected system".

      Not quite in the same realm as coughing up plain-text passwords, I'll admit. But clearly some relevant authorities would set the bar for "access control system" fairly low. And apparently rank incompetence on the part of the site developer/owner appears not to come into things.

      [1] https://news.ycombinator.com/item?id=4808676

      • feralmoan 12 years ago

        Really wish there were better defense attorneys onboard in these cases because at their core these instances boggle the logical mind.

  • rpedela 12 years ago

    Felony for what?

    • msost 12 years ago

      Assuming the user "Injustice" isn't the blog post author's account, yeah they shouldn't be logging into it, even just to prove the legitimacy of an exploit.

philjackson 12 years ago

Despite the warning to the company back in 2010, I'm not sure he should be publishing this. He's putting the 2000-odd users at risk by teaching us how to get their passwords and usernames like that, it's even worse if we can get at email addresses too. I would bet the majority of those registered reuse the passwords.

  • Kequc 12 years ago

    It's a timebomb. If the company won't fix it then the problem gets worse and worse, waiting 4 years before setting it off is long enough.

  • brianpgordon 12 years ago

    I'm certain that publishing this is a bad idea, particularly since he admitted to logging in as a random user. Again and again we've seen that performing trivial actions is treated by the courts as "unauthorized access."

    Weev was convicted to 3.5 years in prison for calling a public API with lots of different keys:

    http://arstechnica.com/tech-policy/2013/03/auernheimer-aka-w...

    In the UK, Daniel Cuthbert was convicted for typing "../../../" in his address bar:

    http://www.securityfocus.com/news/11341

  • bm1362 12 years ago

    It's not particularly sensitive data being jeopardized- isn't it just movie reviews?

    • choult 12 years ago

      Given the prevalence of password reuse, exposing user passwords is never a good idea.

      • mikeash 12 years ago

        Just to drive this home a little more: a lot of your users will use the exact same e-mail address and password on your site that they use for their bank. And while they shouldn't do that, they will, and that's why you should use best practices to protect your users' credentials even if their account on your site is completely unimportant.

        • bm1362 12 years ago

          Ah, yes, I missed the "I would bet the majority of those registered reuse the passwords." from parent.

    • danielharan 12 years ago

      Besides choult's point, users can often be de-anonymized based on just a few ratings. Someone did this by cross-referencing dates in the Netflix data set and those available on one of the bigger sites.

      Suddenly the fact that you were watching documentaries or movies that let you infer their political or sexual proclivities could be determined by outsiders.

victorhooi 12 years ago

Well, it seems they took the entire API down in response:

http://api.criticker.com/

Due to a security breach, the Criticker APIs have been taken off-line for an unspecified amount of time.

We apologize for the inconvenience.

And here I was, looking forward to actually verifying if this stuff was true...

austinz 12 years ago

Wait, just to be clear - so anyone who downloads this app can trivially retrieve the username and password for all 2000+ users of the app? Did I misunderstand the article?

  • k1kingy 12 years ago

    Basically yes. As he did, he managed to get the API key by doing a TCP dump.

    From there he was able to use the key to get the users and plaintext passwords. Very much wtf.

dgarrett 12 years ago

From http://api.criticker.com/

> Due to a security breach, the Criticker APIs have been taken off-line for an unspecified amount of time.

> We apologize for the inconvenience.

octatone2 12 years ago

What the, why? Who thought this matched any sane API authentication pattern?

jbeja 12 years ago

It give me chills when i read this quote:

Returns the password for a user associated with the API account. Note, this can't be used to lookup just any user's password – the user must have been created by the API account.

rdegges 12 years ago

If anyone from the Criticker team is here on HN, I'd be happy to help you guys get this resolved -- my company Stormpath (https://stormpath.com/) provides a really secure way to handle user accounts.

I'll help you guys integrate, or -- if you prefer, I'd be more than happy to dive into your source and help figure out problems and get them resolved. We have a pretty huge team of security experts, and we're all more than happy to help.

I'm randall@stormpath.com if you'd like to chat.

  • austinz 12 years ago

    This looks like something a lot of startups could benefit from, even those who can't be arsed to care one whit about security otherwise.

    By the way, the alt-text for the portraits on your "About" page needs to be fixed.

    • chunsaker 12 years ago

      Thanks! The website is shiny new, and I added this to our list of bugs to squash. Any and all bugs/suggestions welcome --> claire@stormpath.com

  • iconjack 12 years ago

    Does Stormpath have a painless way to extract user data? I worry about lock-in.

    • rdegges 12 years ago

      Yah -- you can use the API to export stuff really easily. We also have export scripts and stuff.

      Furthermore, we'll go out of our way to help you move off the platform if you want.

SideburnsOfDoom 12 years ago

In case anyone is wondering, there are ways to use API keys securely, i.e. without sending them in plaintext on each request.

One common way is OAuth signed requests: http://hueniverse.com/2008/10/beginners-guide-to-oauth-part-... There should be an OAuth library for the language that you are using.

LukeB_UK 12 years ago

I hope that the author notified Criticker about these issues before putting them out there on the internet. Not doing so would be extremely irresponsible and is sort of screwing over the users of Cricketer.

  • mwfunk 12 years ago

    They've already screwed over their users to such a degree with this implementation that the only sane thing to do is to warn all of the user base to stop using it at once and never go back.

    What's described in this article indicates a level of incompetence far beyond any hope of forgiveness by those users. If there was any reason at all to trust the API's designers, then what you describe would be the correct response, but this is very much a case where the only rational response is to tell everyone to leave immediately, forever. It's truly an unforgivable lapse of technical judgement.

    It's not the way it is because of some honest mistake that someone made, like most security bugs are. This was by design, and it's bad enough that there's no reason to believe that the designers are capable of coming up with a better design.

    EDIT: As others have pointed out, he did warn them. Even more WTF then!

    • citricsquid 12 years ago

      I think saying that he "warned them" is a bit dishonest. He said the following as a side note 4 years ago:

          I've just checked and you can obtain the password through an API call 
          after you register a new API user.
      
      They designed this functionality so they clearly knew it was possible, what he didn't do was explain the impact (take public key from app -> request user password) and if he hasn't notified them since that post it's entirely possible that they never had a reason to reconsider that (awful) decision. That post 4 years ago can't really be considered "responsible disclosure".
    • icebraining 12 years ago

      Not trying to excuse Criticker, but from my POV as a user, this isn't exactly Mt.Gox or a bank; it's a website to rate movies, and all the information you put there is already public. All someone can do with my password is rate movies on my behalf.

      Again, this doesn't excuse them, especially since we all know people reuse passwords. I'm just saying that the site is useful even if you know everyone can get in.

      • makaveli8 12 years ago

        A lot of people reuse passwords across multiple sites - so nab their plain-text password + find out their email address, and you likely able to log into various other services using their credentials.

  • pille 12 years ago

    He claims to have notified Criticker in 2010, and links to a post on their forum (username teario):

    http://www.criticker.com/forum/viewtopic.php?f=8&t=2063#p188...

    • 6cxs2hd6 12 years ago

      From a quick glance at their forums, there are no posts about this (yet). It will be interesting to see how users feel about this.

      It will also be interesting to see if the company makes any warning that the average user will understand (e.g. "don't reuse your Criticker password on other sites, especially email or financial, because your password here is not secret, at all").

    • LukeB_UK 12 years ago

      Thanks for that, I skipped over that paragraph.

      • CatMtKing 12 years ago

        I don't think his post was blatant enough for the devs to pick up on it. Seems like the only guy that responded tl;dr'd it. He should have stated very clearly that this is a MAJOR security issue.

        • makaveli8 12 years ago

          Agreed - He didn't even say that it was an issue at all. He seemed more concerned that the users are scoped to particular API keys and that he will lose his reviews.

  • fake-name 12 years ago

    If you read the link, you'll see he did....

    in 2010! It remains unchanged.

    *Beat to the point by pille

Sami_Lehtinen 12 years ago

Well, bad APIs and security is the norm, unfortunately. As example DigitalOcean doesn't use signatures, and uses static API key. Would you consider that to be secure? Especially if we aknowledge all the weakness of SSL/TLS/HTTPS. https://plus.google.com/+SamiLehtinen/posts/1qFhf9fAbU6

tyrick 12 years ago

Raw password storage is more common than we like to believe. A simple way for webapps to communicate that raw passwords are not being stored would be convenient. A small 'NORAWPW' image in the footer perhaps. it would ease my worries, especially with cryptocurrency related webapps.

  • psquid 12 years ago

    Unless the footer image in question was awarded by some kind of auditing body (with links back to their page so a visitor could verify the site really was audited), an idea like that has no fangs - for example, what's to stop a site storing them in plaintext because "it's easier, and we'll fix it when we have time" but throwing the image in the footer anyway to ensure they don't lose users in the meantime?

  • aphistic 12 years ago

    "Designed for IE" "Designed for Netscape" "Designed in Notepad"

    No thanks!

akfanta 12 years ago

Despite all the plaintext password nonsense, I still can't wrap my head around the fact that there is an API call for getting passwords. What legitimate use could it possibly be?

faazshift 12 years ago

Wow... storing passwords in plain text? Even worse, non-encrypted data transport and client accessible credentials? Those "programmers" should be shot!

  • nyrina 12 years ago

    If we started killing people for making mistakes, none of us would be alive.

famo 12 years ago

My opinion is that any company building an API should run at least one bug bounty on it before releasing it to the public.

thailehuy 12 years ago

I'm not sure what is worse, the bad API/app design, or the blog post publicly sharing how to abuse it...

agapos 12 years ago

I am waiting for an API for a specifically designed API-maker software named "Yo dawg".

Kiro 12 years ago

How should an app utilizing an API send the API key so it can't be hijacked with tcpdump?

  • astral303 12 years ago

    You can't really avoid it. If the API key is hardcoded in the client, it's just a matter of time and patience until it's extracted. Never trust the client.

  • CornishPasty 12 years ago

    By using HTTPS/SSL. But the onus of that is on the API provider...

    • thedufer 12 years ago

      It also doesn't help that much - you can still look up the api key in the package, which isn't a whole lot harder. You could probably sign your own cert, tell your device to trust it, and MITM it, too.

joetech 12 years ago

Someone please change the title to "How not to disclose a vulnerability"

teemo_cute 12 years ago

To those of your interested on the topic, leanpub has an ebook you can get for free here:

https://leanpub.com/yourapiisbad

digitalpacman 12 years ago

This post is more about security than just APIs... dislike title. Also.. I don't see how this is an issue. If the user signs up via your app... and you wanted their password. You have it. Sure it's a big deal if someone steals your key... but if you always do it over SSL, they have to steal the "phone" or the "app" that you use. And if they steal the phone... they can use things like "email reset password", because email will most likely be logged in anyway.

  • makaveli8 12 years ago

    The problem is that the app uses the same API key no matter what device it is installed on. If you download the app today you can find the API key and use it to retrieve the passwords for any users that have signed up to Criticker using the app - just as the author has done.

  • ancarda 12 years ago

    >I don't see how this is an issue

    Stealing 2853 user's passwords, which are stored in plaintext, sent over HTTP isn't an issue? This wasn't an SQL injection, the API gives it away.

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection