Съхранявайте чувствителни данни в Silverstripe 3.1

Искам да съхранявам чувствителна информация (главно пароли) в обект с данни в silverstripe. Данните трябва да се съхраняват криптирани в базата данни. Ако извикам това поле в моя шаблон, имам нужда от дешифрирани данни.

Но не знам как да направя това. Може ли някой да ме насочи в правилната посока?

Мерси!


person invictus    schedule 29.09.2013    source източник
comment
съхраняването на данни за паролата с обратим хеш противоречи малко на идеята, че е сигурно? Решение може да бъде използването на ключ за криптиране, но ако този ключ е компрометиран, всичките ви данни са компрометирани, особено след като този ключ трябва да бъде достъпен от сървъра по всяко време, така че е изложен на риск....   -  person colymba    schedule 29.09.2013
comment
Защо искате да наричате това във вашия шаблон? Искате ли да покажете паролата на потребителя? Или просто проверете дали паролата е въведена правилно?   -  person 3dgoo    schedule 30.09.2013
comment
искам да го покажа на потребителя, ако има нужда от него. например паролата за ftp. не е добра идея?   -  person invictus    schedule 30.09.2013
comment
ДОБРЕ. Можете да използвате някои php функции за криптиране и декриптиране, като използвате частен ключ, за да ги съхранявате. Ако паролите са само за 1 влязъл потребител, тогава бих съхранил произволен низов ключ срещу този потребител, който да използвам за криптиране и декриптиране на паролите. Ако имам време, опитвам се да напиша някакъв код и ще го публикувам тук, ако го накарам да работи.   -  person 3dgoo    schedule 01.10.2013
comment
това би било страхотно! Благодаря ти. Все пак ще го пробвам   -  person invictus    schedule 01.10.2013


Отговори (2)


Това, което можете да направите, е да създадете Password DataObject с обекта Member, който има връзка едно към много с обекта Password. Можете да използвате солта на влезлия член с двупосочна функция за шифроване на php, за да шифровате и дешифрирате парола.

Този примерен код използва php mcrypt с член сол за шифроване и дешифриране на паролата.

Класът парола има описание, url, потребителско име и парола. Той съдържа функция за шифроване на даден низ с помощта на даден ключ. Той също така съдържа функция за дешифриране за декриптиране на съхранената парола с помощта на солта на свързания член.

Клас парола

<?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))));
    }

}

Трябва да разширим обекта Member, за да имаме връзка has_many с обекта Password:

MemberPasswordListExtension

<?php
class MemberPasswordListExtension extends DataExtension {

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

Това е необходимо във вашата конфигурация, за да добавите разширението:

_config.php

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

Следва формуляр за добавяне на парола. При изпращане ние шифроваме паролата, като използваме членската сол и функцията за шифроване от класа Password.

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();
}

...

В шаблона на страницата извикваме формуляра и преминаваме през паролите, записани под този потребител. Показваме потребителското име, криптираната парола и декриптираната парола, само за да ни покажем, че това работи:

Шаблон Page.ss

...

<% 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 %>

...

Това трябва да ви даде основа за това, което искате да направите, и трябва да можете да го промените според вашите нужди.

Методът на криптиране е взет от този отговор на stackoverflow: Най-простото двупосочно криптиране с помощта на PHP

Можете лесно да замените друг метод за криптиране/декриптиране с останалата част от този код, както желаете.

person 3dgoo    schedule 02.10.2013
comment
Уау, благодаря ти много. Ще тествам тази вечер, щом се прибера :) После ще пиша резултатите. - person invictus; 02.10.2013
comment
Съжалявам, не можах да го тествам досега :/ Но в момента създавам нова страница със сребърна лента, за да го тествам. Ще публикувам резултатите си след около 15-30 минути - person invictus; 09.10.2013
comment
Хубаво, работи като чар :) Но не отговаря на пълните ми нужди. Потребителят не трябва да може да запазва собствените си пароли. Имам страница за всеки потребител (клиент). И на тази страница аз (администратор) искам да съхранявам паролите за тях. - person invictus; 09.10.2013
comment
Ще трябва само да промените начина, по който въвеждате паролите, независимо дали е чрез преден формуляр, който е видим само за администраторските членове, или чрез администратор на модела в задния край. Останалата част от кода ще работи както е. Програмирах го така, за да можете да тествате дали криптирането/декриптирането на паролата работи. Уведомете ни, ако имате затруднения с програмирането на избраното от вас решение за запазване на парола. - person 3dgoo; 10.10.2013
comment
Добре, управлявам го с администратора на модела. Но има ли начин да се даде възможност на потребителя да редактира предварително избрани записи? Добавих квадратче за отметка към всеки запис, когато е отметнато, потребителят трябва да може да редактира този запис в предния край, когато щракне върху бутона за редактиране зад него. Възможно ли е това? - person invictus; 10.10.2013
comment
Сега имам проблем :/ след създаването на полетата с getCMSFields де/криптирането вече не работи. Започнах нова тема тук: stackoverflow.com /questions/19312702/ може би можете да ми помогнете - person invictus; 11.10.2013

По подразбиране Silverstripe 3.x съхранява пароли с необратим солиран хеш с помощта на Blowfish. Можете да напишете различни класове на PasswordEncryptor, за да се справите с други поведения. Вижте различните класове в framework/security/PasswordEncryptor.php за примери как се прави това. Внедрете PasswordEncryptor_Custom.php някъде във вашата собствена кодова база (т.е. mysite/) и внедрите отново всички функции.

Имайте предвид, че това е много нетипично и противоречи на най-добрите практики за сигурност. Като общо правило, никога не трябва да правите достъпни за никого паролите в обикновен текст, точка. Обратимото шифроване на пароли е по своята същност несигурно, тъй като вие ефективно заменяте една парола в обикновен текст (на потребителя) с друга (ключ в обикновен текст). Винаги е по-добре просто да нулирате паролата с различен хеш.

person cryptopay    schedule 30.09.2013
comment
Мисълта ми беше, че потребителят може да влезе и след това да има достъп до своите пароли, ftp, mysql и т.н. и нямам навика да ги съхранявам като обикновен текст в базата данни. знаете ли сигурен начин за решаване на това? - person invictus; 30.09.2013
comment
Тъй като не го използвате за удостоверяване, достатъчно е да шифровате паролата с някакъв ключ, преди да я съхраните в базата данни. Използвайте хеша на паролата на Blowfish като ключ и извлечете солта от него, след което я осолете допълнително с таен ключ, кодиран в приложението. Всеки, който компрометира вашата база данни, също ще изисква достъп до вашия уеб сървър, за да дешифрира ключа. Ще трябва да декодирате и прекодирате всеки път, когато потребителят промени паролата си. - person cryptopay; 01.10.2013