Storing Account Passwords

I have a need to store account usernames and passwords, not for the Yii application itself, but for Web Account Tracking. I’m assuming these should be encrypted, but obviously I need to decrypt them in the _form. It can’t be a one-way hash in this instance.

Can anyone advise me on the best approach such scenario? I want to make sure I am doing things the most securely as possible.

I’ve seen https://www.yiiframework.com/doc/guide/2.0/en/security-cryptography and https://github.com/nickcv-ln/yii2-encrypter and just wanted a little guidance before I went down the wrong road.

Say I use encryptByPassword(), what data type should be used to store the results? I can’t seem to find any mention in the documentation.

As always, thank you for taking the time to help!

I since tried to put together a simple example to do some testing

public function actionCreate()
{
    $secretKey = 'Testing';
    $model = new ClientsAccounts();

    if ($model->load(Yii::$app->request->post())) {
        \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
        $model->dtCreation = date('Y-m-d H:i:s');
        $model->Username= Yii::$app->getSecurity()->encryptByPassword($model->AccountUN, $secretKey);
        $model->Password = Yii::$app->getSecurity()->encryptByPassword($model->AccountPW, $secretKey);
        if ($model->validate()) {
            $model->save();
            return json_encode(['status' => 'Success', 'message' => 'New record created successfully.']);
        }else{
            $validationErrors = '';
            if ($model->hasErrors()) {
                if ($validationErrors != '') {
                    $validationErrors .= '<br>';
                }
                $validationErrors .= '<div class="col-md-offset-1">' . implode('<br>', $model->getErrorSummary(true)) . '</div>';
            }
            return json_encode([
                'status' => 'Error', 
                'message' => 'Model not valid!',
                'errors' => $validationErrors
            ]);
        }
    } else {
        return $this->renderAjax('create', [
            'model' => $model,
        ]);
    }
}

public function actionUpdate($id)
{
    $secretKey = 'Testing';
    $model = $this->findModel($id);
    if ($model->load(Yii::$app->request->post())) {
        \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
        $model->dtModification = date('Y-m-d H:i:s');
        $model->Username = Yii::$app->getSecurity()->encryptByPassword($model->AccountUN, $secretKey);
        $model->Password = Yii::$app->getSecurity()->encryptByPassword($model->AccountPW, $secretKey);
        if ($model->validate()) {
            $model->save();
            return json_encode([
                'status' => 'Success',
                'message' => 'Record updated successfully.'
            ]);
        } else {
            $validationErrors = '';
            if ($model->hasErrors()) {
                if ($validationErrors != '') {
                    $validationErrors .= '<br>';
                }
                $validationErrors .= '<div class="col-md-offset-1">' . implode('<br>', $model->getErrorSummary(true)) . '</div>';
            }
            return json_encode([
                'status' => 'Error',
                'message' => 'Model not valid!',
                'errors' => $validationErrors
            ]);
        }
    } else {
        $model->Username = Yii::$app->getSecurity()->decryptByPassword($model->AccountUN, $secretKey);
        $model->Password = Yii::$app->getSecurity()->decryptByPassword($model->AccountPW, $secretKey);
        return $this->renderAjax('update', [
            'model' => $model,
        ]);
    }
}

for some reason the decryptByPassword() doesn’t seem to be working. Those fields appear to return nothing? I have validated the Create action does push the encrypted data.

I finally got my example working by searching, but don’t quite understand why it is necessary (to encode and decode base64), below is the functional code should it helps others or if someone would care to explain it further to me (I’d be very grateful).

/**
 * Creates a new ClientsAccounts model.
 * If creation is successful, the browser will be redirected to the 'view' page.
 * @return mixed
 */
public function actionCreate()
{
    $secretKey = 'TestingEncrypt0003282!';
    $model = new ClientsAccounts();

    if ($model->load(Yii::$app->request->post())) {
        \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
        $model->dtCreation = date('Y-m-d H:i:s');
        $model->Username = base64_encode(Yii::$app->getSecurity()->encryptByPassword($model->AccountUN, $secretKey));
        $model->Password = base64_encode(Yii::$app->getSecurity()->encryptByPassword($model->AccountPW, $secretKey));
        if ($model->validate()) {
            $model->save();
            return json_encode(['status' => 'Success', 'message' => 'New record created successfully.']);
        }else{
            $validationErrors = '';
            if ($model->hasErrors()) {
                if ($validationErrors != '') {
                    $validationErrors .= '<br>';
                }
                $validationErrors .= '<div class="col-md-offset-1">' . implode('<br>', $model->getErrorSummary(true)) . '</div>';
            }
            return json_encode([
                'status' => 'Error', 
                'message' => 'Model not valid!',
                'errors' => $validationErrors
            ]);
        }
    } else {
        return $this->renderAjax('create', [
            'model' => $model,
        ]);
    }
}

/**
 * Updates an existing ClientsAccounts model.
 * If update is successful, the browser will be redirected to the 'view' page.
 * @param integer $id
 * @return mixed
 * @throws NotFoundHttpException if the model cannot be found
 */
public function actionUpdate($id)
{
    $secretKey = 'TestingEncrypt0003282!';
    $model = $this->findModel($id);
    if ($model->load(Yii::$app->request->post())) {
        \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
        $model->dtModification = date('Y-m-d H:i:s');
        $model->Username = base64_encode(Yii::$app->getSecurity()->encryptByPassword($model->AccountUN, $secretKey));
        $model->Password = base64_encode(Yii::$app->getSecurity()->encryptByPassword($model->AccountPW, $secretKey));
        if ($model->validate()) {
            $model->save();
            return json_encode([
                'status' => 'Success',
                'message' => 'Record updated successfully.'
            ]);
        } else {
            $validationErrors = '';
            if ($model->hasErrors()) {
                if ($validationErrors != '') {
                    $validationErrors .= '<br>';
                }
                $validationErrors .= '<div class="col-md-offset-1">' . implode('<br>', $model->getErrorSummary(true)) . '</div>';
            }
            return json_encode([
                'status' => 'Error',
                'message' => 'Model not valid!',
                'errors' => $validationErrors
            ]);
        }
    } else {
        $model->Username = Yii::$app->getSecurity()->decryptByPassword(base64_decode($model->AccountUN), $secretKey);
        $model->Password = Yii::$app->getSecurity()->decryptByPassword(base64_decode($model->AccountPW), $secretKey);
        return $this->renderAjax('update', [
            'model' => $model,
        ]);
    }
}

equally effective is using utf8_encode() and utf8_decode(). Is it normal to require these functions? Is there a way to setup the database field so it isn’t required?

Looks like your database can’t save certain characters.

So is there a way to address this? Should I be setting up field using a specific collation? A specific data type? Or is the workaround acceptable/reliable?

I see that if I switch the data type to Blob then I no longer need to use encode/decode functions. Is Blob the data type required by encryptByPassword()? I can’t find anything anywhere in the documentation that discusses data types. Even in the source code, there’s absolutely nothing or I’m looking in the wrong place.

Using blob is a good way since after encryption your data is bytes array.

Being a novice at all of this, can I ask how you know this as I found no mention of data types in any of the documentation I reviewed. I’m just trying to learn how to learn how to use Yii and documentation properly so as to not have so many questions!

There was no mention indeed. Added it: https://github.com/yiisoft/yii2/commit/331d9971857d8c95cf1bf12b1a2f9f8fa83f1125

Usually searching API and reading description helps.

Thank you so very much for all your help!