1

I want to store sensitive informations (mainly passwords) in a dataobject in silverstripe. The Data need to be stored crypted in the database. If i call this field in my template, I need the data decrypted.

But I don't know how to do this. Can someone point me in the right direction?

Thx!

invictus
  • 825
  • 1
  • 9
  • 33
  • storing password data with a reversible hash goes a bit against the idea of it being secure? A solution could be to use an encryption key, but if that key is compromised, all your data is compromised especially since that key needs to be accessible by the server at all time, so at risk.... – colymba Sep 29 '13 at 18:17
  • Why do you want to call this in your template? Do you want to display the password to the user? Or just check if a password has been entered correctly? – 3dgoo Sep 30 '13 at 00:45
  • i want to display it to the user if he needs it. for example the ftp password. not a good idea? – invictus Sep 30 '13 at 14:36
  • 1
    OK. You could use some php encrypt and decrypt functions using a private key to store them. If the passwords are only for 1 logged in user then I would store a random string key against that user to use to encrypt and decrypt the passwords. If I get some time I try to write up some code, and I'll post it here if I get it working. – 3dgoo Sep 30 '13 at 22:34
  • that would be great! thank you. I'll although give it a try – invictus Oct 01 '13 at 05:56

2 Answers2

2

What you could do is create a Password DataObject with the Member object having a one to many relationship to the Password object. You can use the salt of the logged in Member with a 2 way php encrypt function to encrypt and decrypt a password.

This example code uses php mcrypt with the member salt to encrypt and decrypt the password.

The password class has a description, a url, username, and password. It contains a function to encrypt a given string using a given key. It also contains a decrypt function to decrypt the stored password using the connected member salt.

Password class

<?php
class Password extends DataObject
{
    static $db = array (
        'Description' => 'Text', 
        'URL' => 'Text', 
        'Username' => 'Text', 
        'Password' => 'Text'
    );

    static $has_one = array (
        'Member' => 'Member'
    );

    public function decryptedPassword() {
        return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($this->Member()->Salt), base64_decode($this->Password), MCRYPT_MODE_CBC, md5(md5($this->Member()->Salt))), "\0");
    }

    public function encryptPassword($key, $password) {
        return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $password, MCRYPT_MODE_CBC, md5(md5($key))));
    }

}

We need to extend the Member object to have a has_many relationship with the Password object:

MemberPasswordListExtension

<?php
class MemberPasswordListExtension extends DataExtension {

    private static $has_many = array(
        'Passwords' => 'Password'
    );
}

This is needed in your config to add the extension:

_config.php

...
Member::add_extension('Member', 'MemberPasswordListExtension');
...

The following is a form to add a password. On submission we encrypt the password using the member salt and the encrypt function from the Password class.

Page_Controller

...

public function AddPasswordForm() {
    // Create fields
    $fields = new FieldList(
        new TextField('Description'),
        new TextField('URL'),
        new TextField('Username'),
        new TextField('Password')
    );

    // Create actions
    $actions = new FieldList(
        new FormAction('AddPassword', 'Submit')
    );

    return new Form($this, 'AddPasswordForm', $fields, $actions);
}

public function AddPassword($data, $form) {
    if($member = Member::currentUser()) {
        $password = new Password();
        $form->saveInto($password);
        $password->MemberID = $member->ID;
        $password->Password = $password->encryptPassword($member->Salt, $password->Password);
        $password->write();
    }
    return $this->redirectBack();
}

...

In the page template we call the Form and loop through the passwords saved under this user. We display the username, the encrypted password and the decrypted password, just to show us this has worked:

Page.ss template

...

<% if $CurrentMember %>
$AddPasswordForm
<% end_if %>

<% with $CurrentMember %>
<h3>Passwords</h3>
<% if $Passwords %>
<ul>
<% loop $Passwords %>
    <li>$Username $Password $DecryptedPassword</li>
<% end_loop %>
</ul>
<% else %>
<p>No passwords saved</p>
<% end_if %>
<% end_with %>

...

This should give you a base for what you want to do, and you should be able to change it to your needs.

The encryption method was taken from this stackoverflow answer: Simplest two-way encryption using PHP

You could easily substitute a different encrypt/decrypt method with the rest of this code as you desire.

Community
  • 1
  • 1
3dgoo
  • 15,716
  • 6
  • 46
  • 58
  • Wow, thank you very much. I'll test this evening as soon as I arrive at home :) I'll post my results afterwards. – invictus Oct 02 '13 at 12:51
  • Sry I wasn't able to test it until now :/ But at the moment I'm setting up a new silverstripe page to test it. I'll post my results in about 15 - 30 mins – invictus Oct 09 '13 at 12:26
  • Nice it works like a charm :) But it doesn't fit my full needs. The User shouldn't be able to save his own passwords. I've got a page for each user (client). And on this Page I (Admin) want to store the passwords for them. – invictus Oct 09 '13 at 12:35
  • You would only need to change the way the you enter the passwords, whether it is through a front end form that is only visible to admin members, or through model admin in the back end. The rest of the code would work as is. I programmed it like this so you could test that the password encryption/decryption works. Let us know if have any difficulty programming the password saving solution that you choose. – 3dgoo Oct 09 '13 at 21:20
  • Ok I'm managing it with model admin. But is there a way to give the user the possibility to edit pre selected entries? I Added a Checkbox to each entry, when it's checked the user should be able to edit this entry in the front end, when he clicks edit-button behind it. Is this possible? – invictus Oct 10 '13 at 06:41
  • Now I've got a problem :/ after creating the fields wit getCMSFields the de/encryption doesn't work anymore. I started a new topic here: http://stackoverflow.com/questions/19312702/sivlerstripe-password-de-encrypting-doesnt-work perhapes you can help me – invictus Oct 11 '13 at 07:37
1

By default, Silverstripe 3.x stores passwords with an irreversible salted hash using Blowfish. You can write different PasswordEncryptor classes to handle other behaviours. See the various classes in framework/security/PasswordEncryptor.php for examples of how this is done. Implement PasswordEncryptor_Custom.php somewhere in your own codebase (i.e. mysite/) and re-implement all of the functions.

Note that this is very atypical and goes against best practices for security. As a general rule of thumb, you should never make plaintext passwords available to anybody, period. Reversible password encryption is inherently insecure, as you're effectively replacing one plaintext password (the user's) with another (a plaintext key). It is always better to simply reset the password with a different hash.

cryptopay
  • 1,084
  • 6
  • 7
  • my thought was, that a user can login and than he can access his passwords, ftp, mysql, etc. and i don't wont to store them as plaintext in the database. do you know a secure way to solve this? – invictus Sep 30 '13 at 14:39
  • 1
    Since you're not using it for authentication, it's sufficient to encrypt the password with some key before storing it in the database. Use the Blowfish password hash as a key and extract the salt from that, then salt it further with a secret key coded into the application. Anyone who compromises your database would also require access to your webserver to decrypt the key. You'll need to decode and re-encode whenever the user changes their password. – cryptopay Oct 01 '13 at 03:04