Problem/Motivation

One design decision at the moment of the brightcove module is to not depend on other modules. While this is in general not the worst ideas, there are some issues with that.
One example is the way how the module store API/access tokens inside config directly. This is really convenient, but from a security point of view it would not be ideal. People with access to the database could post videos as much as they want.

Proposed resolution

For similiar usecases as well as the usecase of encryption/decryption of data there is the Keymodule out there. It provides an abstraction layer of where to store that kind of sensible data, which allows you, for example, to store that data outside out the webroot in a file.

It would be nice to somehow make it possible to integrate the key module with brightcove in an optional way.

Remaining tasks

User interface changes

API changes

Data model changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dawehner created an issue. See original summary.

tamasd’s picture

I have checked the code of the key module for the D7 version, and it seems to me that it stores the decryption key in either a database or in a file. If the database is compromised, then it is possible to run PHP code (either through activating some code path that runs eval(), or by manipulating the serialized objects in the database). If PHP code can run, then the unlock key is readable.

dawehner’s picture

If the database is compromised, then it is possible to run PHP code (either through activating some code path that runs eval(), or by manipulating the serialized objects in the database). If PHP code can run, then the unlock key is readable.

Well, gladly this cannot happen anymore in Drupal 8, because there is no php_eval module out there. Afaik we store no string inside the DB which can be evaluated. Note: Your attack also just works for write permissions. The issue described for the generic usecase of the key module is also for read access.

tamasd’s picture

I have found multiple tables in D8 that do store data with serialize(). If the class and all its data can be manipulated, it is very likely that at least one class exists that can be used to exploit the website (e.g. saving a php file, or reading a file). I am sure that given enough time and motivation, you can pretty much do anything with a Drupal site if you start manipulating objects in its database.

With that being said, I am all for making the module safer, and if you make a patch that does an optional integration with the key module, I am willing to merge it for D7, and I am sure that the same can be arranged for D8.

dawehner’s picture

Yeah just to be clear, I was just given a suggest what could be done, that's it.

You still argue for the case of a writeable DB though :)

jan.mashat’s picture

Status: Active » Needs work
yce’s picture

Assigned: Unassigned » yce
douggreen’s picture

FileSize
4.39 KB

The reason to do this is so that the secret value can be stored in a secure key, outside of the document root, and outside of the version control repo. Attached is a D8 patch.

douggreen’s picture

Updated patch
* simpler
* fixes bug on API form, referencing getDrupalSecretKey()
* creates the subscription on entity create instead of form submit to handle adding the api client as exported config, but not adding the subscription as exported config, so that the site url can be adjusted when moving config between dev/qa/live.

douggreen’s picture

FileSize
8.04 KB

Oops, part of that patch was deleted, here's another update.

douggreen’s picture

Status: Needs work » Needs review
douggreen’s picture

FileSize
3.59 KB

New patch without moving the creation of the subscription --- I'm no longer certain that needs to be done, and if it does, it should be in a separate patch.

douggreen’s picture

FileSize
5.58 KB

Updated patch removed references to client project, and adds dependency injection to the Form.

nicksanta’s picture

Issue tags: +key-integration

Added key-integration tag to track integration efforts across contrib.

douggreen’s picture

FileSize
5.75 KB

Updated patch for latest dev

douggreen’s picture

douggreen’s picture

FileSize
5.51 KB

updated patch to latest head

douggreen’s picture

use key_select instead of select.

douggreen’s picture

In reply to the initial comment on this thread by @tamasd, the key module supports different key providers, one of them is a file key providers, which does not store anything in the database. Key module also uses a plugin system for creating your own key provider storage. These are the reasons to use key module for storing keys. It gives sites the capability to store keys outside the database in a secure area.

yce’s picture

Status: Needs review » Needs work

Hi,

Looks like the patch that you have provided forces the module to use the key module if that's enabled.
It shouldn't be forced, it should be optional to use it even if it's enabled.

Also please provide a readme how to set up a key for the module initially.

RajatC’s picture

Version: 8.x-1.x-dev » 3.0.0
FileSize
5.77 KB

Creating patch #21 to apply #18 patch changes for D9 compatible module version 3.0.0.

banoodle’s picture

Patch #21 applies OK and gives me the option to use a defined key. But I can't get authentication to succeed.

I suspect I am not formatting my secrets.json file correctly.

I'm trying this.

{"secret_key":"[my_key_here]"}

Is "secret_key" wrong? Is there a a special key name that is expected?

I'm definitely using the right credentials as I can get things to work if I add them the usual way. But I really need to secure the secret key, so I'm hoping I can get this to work.

Thanks for working on this!

banoodle’s picture

A colleague figured out what I was doing wrong. In case it helps someone else, the trick is that the file with the API key should just have the api key in it and nothing else (no brackets or quotes or anything). I was wrongly thinking it had to be structured json.

yce’s picture

  1. +++ b/src/Entity/BrightcoveAPIClient.php
    @@ -175,6 +177,27 @@ class BrightcoveAPIClient extends ConfigEntityBase implements BrightcoveAPIClien
    +  public function getSecretKeyValue($secret_key = NULL) {
    

    The getter shouldn't determine the actual value based on the argument.

    This method should know how to load the secret key.

  2. +++ b/src/Entity/BrightcoveAPIClient.php
    @@ -175,6 +177,27 @@ class BrightcoveAPIClient extends ConfigEntityBase implements BrightcoveAPIClien
    +    if ($secret_key && \Drupal::moduleHandler()->moduleExists('key')) {
    

    Hidden dependency in entity, services should be added via dependency injection.

    Since Drupal entities are not injectables the next closest thing is the storage, but this probably should be handled by a service.

  3. +++ b/src/Entity/BrightcoveAPIClient.php
    @@ -175,6 +177,27 @@ class BrightcoveAPIClient extends ConfigEntityBase implements BrightcoveAPIClien
    +      $key_entity = Key::load($secret_key);
    

    Hidden dependency, also entities should be loaded through their storage.

  4. +++ b/src/Form/BrightcoveAPIClientForm.php
    @@ -191,13 +195,18 @@ class BrightcoveAPIClientForm extends EntityForm {
    +    if ($this->moduleHandler->moduleExists('key')) {
    

    It should be selectable.

    Like if someone would want to use key module and exist it could be selected, but we should let the option open for providing the key directly in configuration.

    Also if the credentials can be stored in the key module I would rather move the Account ID, Client ID and Client Secret to the Key entity as they are belong together.

  5. +++ b/src/Form/BrightcoveAPIClientForm.php
    @@ -191,13 +195,18 @@ class BrightcoveAPIClientForm extends EntityForm {
    +      $form['secret_key']['#type'] = 'key_select';
    

    I wonder doing this would hurt the config schema or not, can you please validate?

To be honest I would rather refactor the client handler part of the module as a service, it's not ideal to have it on the entity.