Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: security

  • Expect the Unexpected

    Expect the Unexpected

    The other day, while reviewing a plugin, I told someone that their code was okay, but it could be better.

    They had this:

    if ( $_POST['value'] == 1 ) {
        $variable = yes;
    }
    if ( $_POST['value'] == -1 ) {
        $variable = no;
    }
    

    And I said they should do this:

    $variable = ( $_POST['value'] == 1 )? 'yes' : 'no';
    

    They asked why, since the only possible input were 1 and -1.

    Users Are Weird

    It’s hard to explain why users are so weird, but they are. Any time you have post data that a user can input, a user will find a way to intentionally or accidentally put in bad data. I think perhaps the best way to explain it is that users are like toddlers. You can baby proof your house, but they’ll figure out how to get into the flour and suddenly your kitchen looks like an episode of Cutthroat Kitchen and good luck cleaning it up.

    The point is this. Even if your data is only meant to be a 1 or a -1, you have to think beyond what the code should be and assume it will, one day, be what it’s it.

    Broaden Your Mind

    The basic rule of any input screen is that users will do what they do. They just will. They use code in ways you didn’t imagine, and that’s okay. And even if you have a check box, which logically cannot be altered beyond checked or un-checked, someone will do something outside your expectations.

    The easiest way to understand it is to think about hackers. The whole reason we sanitize checkbox data is not that we expect a user to make a phenomenal mistake, but we expect a hacker to show up and try to back-door our work. We cannot trust that every user has good intentions. This is even more common in WordPress, since anyone can download your code, examine in for weaknesses, and then attack.

    Angry People Do Bad Things

    If I had a nickel for every time I heard “But an admin would never…” I’d be rich.

    A good admin would never, intentionally, break their own system, this is true. But an admin who was just fired, and hasn’t had their credentials revoked yet? Oh gosh, can they ever be evil. When a person was fired at a job I once had, they went into the test lab, took all the diskettes, and tossed them in the dumpster. The protocol for handling people being fired was changed that day, but all it took was one angry admin, and we had to go dumpster diving for 3.5″ floppy disks.

    No, it wasn’t fun.

    Trust No Data

    I never trust data. Not even on code only I use. I always assume I can be tricked into doing something dangerous, or that I’ll make a mistake while using a system. Humans make mistakes. You can’t trust them to be right all the time, and you can’t trust them to be good all the time.

    That means it becomes our responsibility, as developers, to do the following:

    1. Make sure the data entered is sanity-checked
    2. If it’s not sane, fallback to a safe default or throw a good error

    But never, ever, trust anyone to be right all the time. Especially you.

  • Secure Mindsets in Plugins

    Secure Mindsets in Plugins

    At WordCamp Europe last week, I talked about the basics of plugin development. Since I had a mixed bag of experiences, I decided not to actually write a plugin in the class, but instead I took Hello Dolly and edited it. I discussed how the plugin worked, that an action called a function, which returned a value, and showed the interconnectivity. In this way, the attendees could understand the big picture of how code comes together.

    But at the end, with five minutes, I touched on an important aspect of plugins that Hello Dolly doesn’t do much with, because it doesn’t have to.

    I talked about security.

    Past You

    In the past, you probably done insecure things. Have you ever left your car unlocked in the driveway while you ran the groceries inside? We all do things that are insecure or unsafe. This is normal. Similarly, we have done insecure code. In the past, all of us, when we begin, we write code to perform actions without thinking about how it will be used globally. We don’t worry about safe, we worry about functions.

    There’s nothing wrong with this. We are often focus driven designers, fueled by passion and desire, so we want to do and not worry about the details.

    This Morning’s You

    That said, when we do work in that way, we get ourselves into trouble when we ignore security. We assume people will only use the code in the right way, because it’s obvious what is right and what is wrong. I try not to say ‘obvious’ or ‘simple’ when talking about code or interfaces, because they are absolutely never, not once, obvious or simple. When I got my Apple Watch, the UX of Force Touch wasn’t obvious to me. It’s not simple now, since it can be a bit touchy, but it’s not difficult.

    In the same vein, we all know that users do weird shit. Really weird shit. They put text in fields that should only gen numbers. They put numbers in for email. They copy paste without thinking. And you know that. You’ve seen it.

    The Right Now You

    Having read that, you’re hopefully thinking “how can I make my code secure?”

    When we talk about basic security, we mean four things:

    1. Validate your data
    2. Sanitize what you save
    3. Escape what you output
    4. Verify a human meant to do it

    That’s it. Make sure a date is a date and an email is an email. Make sure you save the data in a way that doesn’t put other data at risk. Remove any possibly dangerous characters from what you show to users. Always make sure someone meant to do the action. WordPress has over a dozen Sanitize and Escape functions to help make sure you save the right data and it has nonces to help make sure you save when you should.

    They’re very complex, but at their heart, they do those four things.

    Future You

    The you of tomorrow will appreciate the you of today, if you remember to never trust your data. People typo. People make mistakes. People do bad things on purpose. All of that just happens. And if today, you learn how stop those bad things, tomorrow’s you will look back on you with love and thanks. Your users will thank you. Your next future will love you even more.

    Security isn’t just https and good passwords. It’s a mindset to remember that anything passed to your code might be attacked. It’s a mindset that good users do bad and dumb things. It’s a mindset that mistakes happen. And it’s a mindset that being aware of the whole of your code, how it all comes together, must always include validation, sanitization, escaping, and nonces.

  • Custom Alexa Skills and WordPress

    Custom Alexa Skills and WordPress

    Before you start, please note that there is no Amazon Alexa SDK for PHP. And this is a big problem.

    An SDK is a software development kit that helps standardize the development of apps for the software. Using an SDK is basically using a standard library that everyone can access and call and not reinvent the wheel all the bloody time. And Amazon, for whatever reason, has decided that they’d rather push their Lambda hosting, which yes they charge you for, instead of clearly and cleanly document PHP code. Node.js? No problem. PHP? You’re on your own.

    Rant aside, I have now a custom Amazon Skill, self hosted, and powered by WordPress.

    Amazon’s Requirements

    On Monday I showed you how to build a very generic skill. It had no options, and it was actually missing a critical piece. You see, Amazon has six basic requirements to be an app:

    1. The service must be Internet-accessible.
    2. The service must adhere to the Alexa Skills Kit interface.
    3. The service must support HTTP over SSL/TLS, leveraging an Amazon-trusted certificate.
    4. The service must accept requests on port 443.
    5. The service must present a certificate with a subject alternate name that matches the domain name of the endpoint.
    6. The service must validate that incoming requests are coming from Alexa.

    The first five are pretty normal. If it’s not internet accessible, its not going to work. Same with the adherence to the skills kit interface. But that last one was surprisingly difficult and annoying. Mostly because of that lack of a standardized PHP SDK.

    Basically there isn’t a standard way to validate that incoming requests are coming from Alexa, but boy howdy, are there requirements.

    Validating Requests for Alexa

    While it says the requirement is to validate the requests, that’s only one aspect of the game. The three basic parts are these:

    • Verifying that the Request was Sent by Alexa
    • Checking the Signature of the Request
    • Checking the Timestamp of the Request

    And none of those are really well documented for PHP. Thanks.

    The Code

    In Monday’s post, I framed out the majority of the code that will be used. The change will be in this section:

    public function last_post_rest_api_callback( $data ) {
    	$response = $this->last_post();
    	return $response;
    }
    

    It now shows this:

    public function bury_your_queers_rest_api_callback( WP_REST_Request $request ) {
    	$date = ( isset( $request['request']['intent']['slots']['Date']['value'] ) )? $request['request']['intent']['slots']['Date']['value'] : false;
    	$validate_alexa = $this->alexa_validate_request( $request );
    	if ( $validate_alexa['success'] !== 1 ) {
    		$error = new WP_REST_Response( array( 'message' => $validate_alexa['message'], 'data' => array( 'status' => 400 ) ) );
    		$error->set_status( 400 );
    		return $error;
    	}
    	$response = $this->last_post( $date );
    	return $response;
    }
    

    This makes two changes. First it’s grabbing the date from the weirdly stored JSON POST from Alexa and passing it to my last_post function. That code I’m skipping since taking the date, parsing it, and changing your output from last_post is beyond the score. No, I’m going to concentrate on the alexa_validate_request function.

    You should take note of the success check if ( $validate_alexa['success'] !== 1 ) however. You must use a rest response with a 400 because Amazon is very picky.

    alexa_validate_request

    The brunt of the validation is to check if the URL came from Amazon, if the URL is on the certificate chain, if the certificate is legit, and finally if the request was made in the last 60 seconds. Which is a lot to look for.

    In order to write this function, I forked Rich Bowen’s Validate Echo request via PHP code for WordPress. This takes into account some WordPress code that isn’t otherwise available:

    function alexa_validate_request( $request ) {
    	$url            = $request->get_header( 'signaturecertchainurl' );
    	$timestamp      = $request['request']['timestamp'];
    	$signature      = $request->get_header( 'signature' );
    
    	// Validate that it even came from Amazon ...
    	if ( !isset( $url ) )
    		return array( 'success' => 0, 'message' => 'This request did not come from Amazon.' );
    
    	// Validate proper format of Amazon provided certificate chain url
    	$valid_uri = $this->alexa_valid_key_chain_uri( $url );
    	if ( $valid_uri != 1 )
    	    	return array( 'success' => 0, 'message' => $valid_uri );
    
    	// Validate certificate signature
    	$valid_cert = $this->alexa_valid_cert( $request, $signature, $url );
    	if ( $valid_cert != 1 )
    	    	return array ( 'success' => 0, 'message' => $valid_cert );
    
    	// Validate time stamp
    	if (time() - strtotime( $timestamp ) > 60)
    		return array ( 'success' => 0, 'message' => 'Timestamp validation failure. Current time: ' . time() . ' vs. Timestamp: ' . $timestamp );
    
    	// If there was no error, it's a success!
    	return array( 'success' => 1, 'message' => 'Success' );
    }
    

    Within that function, I reference two more: alexa_valid_key_chain_uri and alexa_valid_cert which parse the chain and validate the certificate.

    function alexa_valid_key_chain_uri( $keychainUri ){
    
        $uriParts = parse_url($keychainUri);
    
        if (strcasecmp( $uriParts['host'], 's3.amazonaws.com' ) != 0 )
            return ( 'The host for the Certificate provided in the header is invalid' );
    
        if (strpos( $uriParts['path'], '/echo.api/' ) !== 0 )
            return ( 'The URL path for the Certificate provided in the header is invalid' );
    
        if (strcasecmp( $uriParts['scheme'], 'https' ) != 0 )
            return ( 'The URL is using an unsupported scheme. Should be https' );
    
        if (array_key_exists( 'port', $uriParts ) && $uriParts['port'] != '443' )
            return ( 'The URL is using an unsupported https port' );
    
        return 1;
    }
    
    /*
        Validate that the certificate and signature are valid
    */
    function alexa_valid_cert( $request, $signature, $url ) {
    
        $md5pem     = get_temp_dir() . md5( $url ) . '.pem';
        $echoDomain = 'echo-api.amazon.com';
    
        // If we haven't received a certificate with this URL before,
        // store it as a cached copy
        if ( !file_exists( $md5pem ) ) file_put_contents( $md5pem, file_get_contents( $url ) );
    
        // Validate certificate chain and signature
        $pem = file_get_contents( $md5pem );
        $ssl_check = openssl_verify( $request->get_body(), base64_decode( $signature ), $pem, 'sha1' );
        if ($ssl_check != 1 ) return( openssl_error_string() );
    
        // Parse certificate for validations below
        $parsedCertificate = openssl_x509_parse( $pem );
        if ( !$parsedCertificate ) return( 'x509 parsing failed' );
    
        // Check that the domain echo-api.amazon.com is present in
        // the Subject Alternative Names (SANs) section of the signing certificate
        if(strpos( $parsedCertificate['extensions']['subjectAltName'], $echoDomain) === false) {
            return( 'subjectAltName Check Failed' );
        }
    
        // Check that the signing certificate has not expired
        // (examine both the Not Before and Not After dates)
        $validFrom = $parsedCertificate['validFrom_time_t'];
        $validTo   = $parsedCertificate['validTo_time_t'];
        $time      = time();
        if (!($validFrom <= $time && $time <= $validTo)) {
            return( 'certificate expiration check failed' );
        }
    
        return 1;
    }
    

    A Word About Testing…

    The problem with all this weird code is that the only way to test is to use Amazon’s testing platform and that doesn’t actually throw back errors. The testing environment is fun, because you can type in ‘when was last post’ and it prepends “Alexa, ask HalfElf…” for you. And it shows you exactly what JSON it’s passing to your API and what your API retuned.

    But…

    In the event your API throws an error, you don’t get to see what the error was. No, you get a message saying that the API returned an invalid output.

    Basically the Amazon API has no actual debugging if you’re trying to debug the connection requirements.

    There may have been a lot of swearing involved on my end.

  • Access: Denied or Granted?

    Access: Denied or Granted?

    One of the topics I discuss regularly with developers it that of access. When writing any code, we must always consider who should have access to it. Not in the ‘who can look at my code?’ aspect, but that of who can run the code.

    This happens a lot with plugins and themes when people create their own settings pages. While I’m the first to admit that the settings API in WordPress is a bag of wet hair that makes little logical sense, using it gives you access to a lot of built in security settings, such as nonces.

    But as I often tell people, a nonce is not bulletproof security. We cannot rely on nonces for authorization purposes.

    What is a Nonce?

    A nonce is a word or expression coined for or used on one occasion. But in security, a nonce is an arbitrary number or phrase that may only be used once. Due to it’s similarity to a nonce word, it reuses the name. In WordPress, it’s a pseudo-random number created on the click of (say) a save button, to ensure that someone had to press the button in order to run the function.

    For example. If your settings page has a nonce, then the nonce is generated on click and passed to the function(s) that validate and sanitize and save. If the nonce doesn’t check out, then WordPress knows someone didn’t press a button, and it won’t run the save. This prevents someone from just sending raw data at your code.

    Why isn’t that enough?

    With just a nonce, anyone who has access to the page can save data. This is okay when you think about something like a comment form or a contact form. Those are things that need to be accessible by non logged in users, right? What about the WordPress General settings page? The one that lets you change the URL of the website? Right. You only want that to be accessible to admins. Imagine if all logged in users could change that one. Yikes!

    In order to protect those pages, you have to consider who should have access to your code.

    1. Are the users logged in or out?
    2. What user permissions should be required?
    3. How much damage can be caused if the data is changed?

    That’s it. That’s all you have to ask. If it’s a contact form, then a nonce is all you need. If it’s a site definition change, then you may want to restrict it to admins or editors only.

    The Settings API

    When you use the settings API, some of this is made pretty straightforward for you:

    add_action( 'admin_menu', 'my_plugin_admin_menu' );
    function my_plugin_admin_menu() {
        add_options_page( 'My Plugin', 'My Plugin', 'manage_options', 'my-plugin', 'my_options_page' );
    }
    

    In that example, the third value for the options page is manage_options which means anyone who can manage site options (i.e. administrators) can access the settings page.

    The problem you run into is if you want a page to do double duty. What if you want everyone to see a page, but only admins can access the settings part? That’s when you need to use current_user_can() to wrap around your code. Just check if a user can do a thing, and then let them in. Or not.

    What Permissions are Best?

    In general, you should give admins access to everything, and after that, give people as little access as possible. While it may be annoying that an editor can’t, say, flush the cache, do they really need to? You have to measure the computational expense of what’s happening before you give access to anyone. It’s not just “Who should do a thing?” but “What are the consequences of the thing?”

    Look at the cache again. Flushing a cache, emptying it, is easy. But it takes time and server energy to rebuild. By deleting it, you force your server to rebuild everything, and that will slow your site down. An admin, who has access to delete plugins and themes, should be aware of that. An editor, who edits posts and menus, may not. And while some editors might, will all?

    This gets harder when you write your code for public use. You have to make hard decisions to protect the majority of users.

    Be as prudent as possible. Restrict as much as possible. It’s safer.

  • You Are Not Psychic

    You Are Not Psychic

    The other day I hear someone mention that they were securing software that they didn’t even have the words for 5 years ago. That reminded me of how fast technology moves. Things that didn’t exist last year are vulnerable today, and the discovery of those things only happens faster as we invent weirder and weirder ways of reinventing the wheel.

    The Myth of Perfection

    A well known saying is that the perfect is the enemy of the good. We take that to mean that if we wait until a thing is perfect, we will never feel it is done enough and ready enough for the world. In Open Source technology we’re fond of releasing and iterating, accepting the lack of perfection and aiming instead for the minimum. What is ‘good enough’ to let people use our work and improve on it?

    Perfection doesn’t exist. There is nothing on the planet that is perfect and there never will be. But accepting this doesn’t mean we allow imperfection and danger into our lives.

    The Balance of Reality

    Everyone screws up code, no matter how awesome a professional you are. Accept it 🙂

    I said that nearly three years ago, and I’ve argued before that it’s okay to screw up. I really do believe that making mistakes isn’t a bad thing. But at the same time, many people understood that to mean I was alright with shipping code that I knew was bad. This is not at all the case.

    If you know your code is bad or insecure, you fix it. Period. You don’t let things you know are bad out the door. But you do release things that work and perhaps lack all the features you want. There’s a difference between releasing bad code and releasing imperfect code.

    The Attack of Security

    To turn this on its ear a little, if someone comes up to you and says “This code is wrong, you should do this other thing.” then you have a choice. You can listen and believe them and study if they’re right and test it and fix it, or you can ignore it.

    When someone you respect tells you those things, you’re inclined to believe them. But at the same time, your heart takes a hit because “this code is wrong” sounds a lot like “this code is bad.” And that sounds like “you wrote bad code” and that feels like “you’re a bad coder.”

    That slope slipped right down, didn’t it? It’s a reality. It’s in our nature to take admonishments of our work as a personal attack, even if they are rarely meant that way. I can count on my hands the number of times I’ve actually told someone they were a bad coder. I can count on one hand the number of times I’ve told someone who wasn’t me that they’re a bad coder. I’ve certainly said it to myself a lot. I believe I’ve told one person directly that I thought they were a bad coder.

    I don’t think they actually understood what I meant… Which says something.

    The Shield of Arrogance

    We are not psychic. If you are, please let me know who to bet on for the World Series. Being humans, and therefore fallible, we cannot be so arrogant as to presume we know all the possible ways our code might be vulnerable. Technology moves so fast that what looks safe today may turn out to be terrible dangerous tomorrow.

    Knowing this, knowing we are imperfect, we know that our fellow humans are also imperfect. The greatest danger to our security is ourselves. And that means, as developer writing code to be used by others, it’s incumbent upon ourselves to protect our fellow humans from innocent mistakes.

    You are not psychic

    You don’t know what will be insecure next. You can’t. So secure your code as best you can and secure it better if people point out your shortcomings. Learn. Improve. Protect.

  • A Case for REST API

    A Case for REST API

    WordPress 4.7.1 and 4.7 were vulnerable via the REST API. Any unauthenticated user could modify the content of any post or page on a site. Since the release of the information, a surprisingly large number of users failed to update to 4.7.2 and, thus, were hacked.

    I say surprisingly because WordPress enabled automatic updates quite a while ago (WordPress 3.7), which will automatically secure your WordPress install. There have been 18 automated releases since then (which is why we have 3.7.18) and the vast majority have addressed security in one way, shape, or form.

    But this post isn’t about the reasons why someone might need to disable the automatic updates. No, this is about the argument I saw stem from the vulnerability, whereby people said it was proof the REST API should be disabled by default.

    And to them I say “No.”

    The REST API Probably Has More Vulnerabilities

    Look, I’m not going to lie to you. The odds are high that the REST API, which is a very new feature, probably has some serious issues still. But, as my friend Helen pointed out to those arguing for it to be disabled by default.

    Why should this be treated differently from XML-RPC? Have you gone through the history of the XML-RPC setting?

    While the REST API may introduce new vulnerabilities to WordPress, and even ones that are horrifyingly accessible to non-logged in users, it is not the first nor the last feature WordPress has added that puts a site at risk. The API, being brand new and not used or tested as much as other aspects of WordPress, is going to be dangerous to exist, but realistically not more or less than any other part of WordPress.

    Go through the list of all WordPress security releases. A lot of issues have been fixed. This is just the first one for the REST API.

    In 2008, XML-RPX in pre-2.3.3 systems allowed remote attackers to edit posts of other blog users, if registration was enabled. That’s a long time ago, and since then the majority of the exploits have revolved around DDoS and pingbacks. But yes, back in the day, this new feature was also problematic.

    Do You Trust WordPress?

    Everyone makes mistakes. Every code has bugs. Everything is vulnerable. The question you have to ask is not “Why did WordPress let this happen?” nor “Why did they put me in danger?” but “Did they handle this well?”

    The heart of the matter is not if you trust WordPress not to screw up, but that you trust them to react responsibly, quickly, and with the appropriate concern. Some security issues are massive. Others are not. With over 26% of the internet using WordPress, fixing the security issues quickly and properly is a huge concern.

    So you have to ask “Do I trust WordPress to fix security issues?” And “Do I trust WordPress has my best interests, with regards to security, at heart?”

    I do, but it’s a question of risk.

    Risk = {si, Îģi, xi}

    My father, a risk analyst, asks three important questions:

    • What can go wrong?
    • How likely is it?
    • What are the consequences?

    Obviously a lot can go wrong. So much, in fact, that it can be impossible to wrap your head around the vastness of the possibilities and subsequent probabilities. Even just listing the things you think might go wrong is incomplete. You know you’re not thinking of everything, so you have to start with the big picture.

    Most of us aren’t capable of calculating the risk and reliability of WordPress. Those Six Sigma experts aren’t either. There’s no way I could actually explain well enough how to determine the risk of using WordPress. If I could, I’d start with asking people “What can go wrong if I disable automatic updates?” and “What can go wrong if I don’t disable automatic updates?”

    The likelihood of the REST API being vulnerable is a little higher than other aspects of WordPress core, but much lower than plugins and themes. The consequences are generally higher than that of plugins and themes, but there’s an extra factor you must consider.

    • How quickly can it be fixed?

    If you leave WordPress auto-updates on, then the answer is “As quickly as humanly possible.” And that, I feel, lowers the overall risk.

    Planned Disclosure

    To those arguing WordPress should have told everyone sooner, this is not the first time WordPress waited a while before announcing a security issue. Take, for example, The Case of the Trojan Emoji. That’s not a Sherlock Holmes mystery, that’s the true case of where WordPress hid a major security fix inside the additions of emoji support.

    There’s a big difference between the Trojan Emoji in 4.2 and the RESTless Backdoor we faced in 4.7, and that is the exploitability. The vulnerability fixed with emojis was hard to do. The one in the API was super easy. In both cases, however, the moment the vulnerability is disclosed, a ticking clock begins to see when people get hacked.

    Sometimes folks tell me I’m hyperbolic or exaggerating when I say ‘attacks will begin within minutes.’ I think that my claim was proven valid, considering how many sites were hacked, and how quickly it happened. Within days of the announcement,

    Remember, security is nuanced. It’s never as simple as “Hey, I found a vulnerability! Patch it!” It requires testing, validation, more testing, and more testing. A good patch doesn’t introduce worse problems (yes, that’s happened before).

    Rarely Used Code Is More Vulnerable

    I bring this guy up every time people argue why WordPress turns on features by default. The WordPress argument is that if they don’t turn it on, people won’t use it. The reason that matters can be found in the works of Herbert Hecht.

    Hecht wrote papers about rare conditions and their effect on software failures. The tl;dr summary for you is this: Rarely used code fails more often.

    Now, Hecht specially was referring to the early days of software use, which the REST API certainly falls under, but the basic philosophy is valid. The less the code is use, the more at risk it is, specifically because it’s used so rarely. People are less familiar with it, they don’t know how to fix it or even test it for all the possibilities, because they don’t yet know what they are.

    Are those reasons to not use the REST API? Not always. You have to consider the risk of using it for yourself. Will your site go down? How bad is that if it happens? Are you doing everything you could to protect yourself?

    Should You Disable The REST API?

    No. Unless you’re certain you’ll never use it, ever, leave it on. It will be fixed, and as long as you apply security patches promptly, you’ll be fine.