4

My plugin is Mailer.app for WordPress, I'm 85% completed and I'm focusing on security before release. Before the questions, I should outline the plugins architecture:

  • The plugin is able to take in username & password and relative imap/smtp server details.
  • The details are validated and made sure that correct imap/smtp are entered (valid connection(s) made)
  • The server details + email are encrypted using the EKEY stored in the class.client.php as CONST
  • The password is encrypted (cannot be hashed as need as plain text for imap/smtp) and stored in a cookie using a CKEY stored in the class.client.php.

  • Data is decrypted using both the cookie and the user data.

Now onto the security questions of WordPress. I been working with wp for about 3 years and can't understand these of find any info on them:

  • Can other plugins access my plugin code? e.g. require("../plugins/mail/class.client.php') and call new Client()? If so, how do I prevent it and why is this allowed?
  • Can other plugin read the contents of the file as I'm storing the encryption key in Client class? If so can you recommend a place to store that so that only Client() class of this plugin can access this?
  • I'm using current_user_can() and nonces but is this enough for add sufficient security to AJAX? can nonces be expired ? and where do I read more about them related to security, ajax & web apps.
  • Can multisite create any additions problems from my scenario?.

Let's have a look an example of my code:

class.client.php

final class Client {
    const SALT = "bsas8D889b8989sHBsd"; // hash salt
    const EKEY = "23123asdas9dsbbad96"; // db encryption key
    const CKEY = "b797a78skj15hjhHJDa"; // cookie encryption key
    private static function GetUserData(){
        return $this->decrypt_data()
    }
    public static function StoreUserData($data){
        return $this->validate_and_store();
    }
    public static function GetEmails(){
        return $this->show_emails($this->GetUserData());
    }
}

class.admin.php

final class Admin {
    public function __construct(){
        add_menu_page('mlr', 'mlr', 'manage_options', 'mlr', array($this,'admin_page'));      
    }
    public function admin_page(){
        $user = new Client();
        echo $user->GetEmails();
    }
}

What my ultimate goal is, other plugins be it infected(backdoor etc) or not cannot access the username/password/mail of my email, that is the main part of the question. The user data that encrypted and stored in the database can only be decrypted using using Cookie and $key; $key being the must vulnerable item.

Sorry for the extra long post but I need to get these questions of my chest and hopefully some insight & help.

Thanks

6
  • 5
    no cookie that is transmuted over HTTP is secure in any way, there is no point in pretending otherwise Feb 12, 2016 at 14:52
  • 6
    Your logic that if the cookie is only set on the path /wp-admin/setsec/ it will be "more secure" is flawed - the moment you load WordPress, all plugins and themes will once again have access to that cookie. Focus on your cookie design (not revealing or storing any sensitive info, only random hashes/session ID's that can be destroyed server side), and enforcing site-wide SSL. Feb 12, 2016 at 16:02
  • 3
    Anything in WordPress can basically access pretty much anything else. You can't really hide stuff from other code running in WordPress. In the worst case any code can just read (as in read file as text) or even edit the raw PHP file instead of accessing stuff on runtime.
    – kraftner
    Feb 17, 2016 at 8:20
  • 7
    This issue seems to transcend WordPress and is more relevant to PHP - as what others have said, if you've got a rogue script on your server, you're pretty much screwed - it'll be able to read & do anything & everything that any other script can do. Feb 17, 2016 at 10:23

1 Answer 1

2

What my ultimate goal is, other plugins be it infected(backdoor etc) or not cannot access the username/password/mail of my email, that is the main part of the question.

The only way to be sure of this is to not store them in a manner than can be automatically decrypted in the database/filesystem - which is to say, not store them in plain-text or an automatically decryptable fashion at all.

I'd recommend concatenating/hashing your own security salts and keys with those configured for WordPress itself - you should never distribute a plugin that uses hard-coded salts as anyone with the plugin is basically handed the keys to whatever's been hashed for every installation. By adding in the WordPress installation's own salts, should you discover that your plugin is vulnerable you can update the salts and invalidate credential stores of all installations when the plugin update is pushed. If an individual installation becomes compromised, a user can change their WordPress salts and likewise invalidate their credentials without altering the plugin.

Can other plugins access my plugin code? e.g. require("../plugins/mail/class.client.php') and call new Client()?

Yes.

If so, [...] why is this allowed?

It's not "allowed" so much as it is a consequence of interpreted scripting environments. "Extending WordPress" with themes and plugins is just that - it's modifying WordPress's execution using raw source to achieve the desired outcome. I know of no interpreted language that actually provides reliable mechanisms to "lock" portions of source-script from other portions within the same code-base. Operating systems, sure.

Rather this responsibility falls onto the execution environment and whoever controls it.

How do I prevent it?

It may be possible to achieve using some seriously complex sand-boxing and running different portions of WordPress in different threads - but this is not at all how WordPress is designed, and would take heavy environment re-configuration to boot. Even then, it would still be susceptible to some variety of attack - despite Google Chrome's sandboxed JavaScript, malicious code still emerges capable of defeating the measures.

As with all information security, it should be assumed that if the environment is compromised, so too is everything in and on it, regardless of security measures in place. Even binary viruses in sandboxed environments and those executed in virtual operating systems can break out of their confines to harm the host system, if designed with such scenarios in mind.

If the consumers of your plugin fail to properly secure their WordPress installations or install compromised code, there is no portion of the filesystem or database that can be considered "safe" for critical information to reside. The same as if a virus finds it's way onto your computer, no program or document can be trusted to remain unadulterated or unexposed - if you store passwords in a plain-text file, you must assume that all relevant accounts are compromised or vulnerable. Here as everywhere else in the IT security world, users should not install executables that they do not trust or understand - those who do not have a good basis to differentiate between trustworthy or well-implemented programs should have a limited ability to acquire and/or install such items.

In short, if you yourself do not directly control the WordPress installations on which your plugin is installed, you cannot prevent your plugin from becoming compromised beyond following good security practices in your implementation.

Can other plugin read the contents of the file as I'm storing the encryption key in Client class?

Yes. In fact, any plugin could parse the WordPress installation's wp-config.php file and obtain the database information and salts should it's author desire. The thing is, a plugin needn't even do that to compromise an installation as the PHP and WordPress environment already give plugins what amounts to free-reign over the database and filesystem to achieve their ends, insofar as the database and filesystem themselves permit. Without these abilities, plugins would be extremely limited in scope.

If so can you recommend a place to store that so that only Client() class of this plugin can access this?

No. Credentials stored and/or transmitted as plain-text are never completely "safe", period.

If your application requires such storage/transmission, then the credentials can only be as safe as the environment in which they're stored. You can add additional hoops to obfuscate the credentials, but the fact remains that if your code has everything it needs to decrypt the credentials, then so too does any other code within the environment. It is essentially the same as storing an encrypted file containing passwords on your computer alongside a shell script that decrypts the file as soon as executed. The best way to keep them safe is to secure the environment.

I'm using current_user_can() and nonces but is this enough for add sufficient security to AJAX?

It depends on the specifics of your application and what's being transmitted via AJAX. Generally, these mechanisms when implemented properly are sufficient to validate that AJAX requests are being made from a consistent source. However, they in and of themselves are only a component of AJAX security. As general rules of thumb:

  • Do not take any action until the request is "sufficiently" verified, including the use of current-user_can(), check_ajax_referer()
  • Escape, validate, and sanitize all the things that comprise dynamic data. These practices are imperative to prevent SQL injections, arbitrary PHP execution, and delivering malicious JavaScript to visitors. This includes $_GET, $_POST, and $_COOKIE data as well as anything retrieved from the database that will be evaluated as PHP or sent to the browser. Learn which WordPress functions handle the tasks for you - but when in doubt, perform them yourself until you can be sure.
  • If you control the server environment, Secure your site with an SSL certificate and operate over the HTTPS protocol in order mitigate the chances of man-in-the-middle attacks (the Let's Encrypt project is well on it's way to offering trustworthy certificates for free).
  • Ensure that your error-handling is implemented in such a manner that if your server-script chokes or is accessed directly by a client, no sensitive data is spat back to the browser.

Can nonces be expired ?

Yes - WordPress provides the nonce_lifetime filter for this purpose. By default a WordPress nonce is valid for 12-24 hours.

Can multisite create any additions problems from my scenario?

It depends on how your plugin is installed and you intend for it to be used in a multisite environment - the potential "problems" that could arise might actually be desire-able outcomes depending on what you're gunning for.

You may want to store mail credentials as user or site-specific data depending on who should have access to which mail - you may even want to implement custom roles and capabilities to provide finer-grained access to mailboxes.

2
  • 1
    Great answer, but I must me ask. If the system is compromised is there even any point of encrypting the username/password/emails? The only security I can think of is cookies to store a randomly generated key and no other user can access there data without that cookie. Is that the maximum security that a Web Mail app that needs to store username/password has or is even that overkill. Any input on this would be great, I spend far to long researching and need to complete this plugin already.
    – Kivylius
    Mar 7, 2016 at 18:28
  • 1
    Pardon the late reply - maximizing security at every layer still has merit. Think of security like a pyramid or Jenga tower - by stabilizing each level as best you can, you can prevent the entire structure from crumbling when the layers above it topple. In this specific instance, however, the "layer" below your plugin is comprised of the database and filesystem. Encrypting the credentials won't do anything in the event of a compromised database/filesystem or malicious code in another plugin, but it may keep them safe from higher-"layered" threats; say, a curious/prying end-user.
    – bosco
    Apr 21, 2016 at 2:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.