Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Caching of decrypted data #46

Merged
merged 14 commits into from
Apr 26, 2016

Conversation

svendecabooter
Copy link
Contributor

First draft to tackle the caching of encrypted data issue (see #17).

This PR:

  • adds a setting to the field storage field_encrypt settings to decide whether this particular encrypted field should be excluded from (render) caching.
  • adds a first attempt at defining tests to test the cacheability of the encrypted data.
  • implements hook_entity_view to set the cache max-age setting to 0 conditionally.

@@ -14,6 +14,9 @@ field.storage.*.*.third_party.field_encrypt:
encryption_profile:
type: string
label: 'Encryption profile'
cache_exclude:
type: boolean
label: 'Exclude from cache'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit ambiguous. We're only focusing on render cache, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's broader than just render cache. When caching the entity object itself, unencrypted field data also shouldn't be stored in the (database) cache...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think uncacheable would be a better name. It'd also fit in better with the terminology in Drupal core.


// If cache_exclude is set, set caching max-age to 0.
if ($storage->getThirdPartySetting('field_encrypt', 'cache_exclude', TRUE) == TRUE) {
$build[$field->getName()]['#cache']['max-age'] = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

@svendecabooter
Copy link
Contributor Author

TODO:

  • Figure out if this approach is OK.
  • Figure out how exactly to test the other caching layers defined by Wim

@svendecabooter
Copy link
Contributor Author

Extra logic and test added to fix caching on entity level, in 'cache.entity'.

$form['field_encrypt']['field_encrypt']['cache_exclude'] = [
'#type' => 'checkbox',
'#title' => t('Exclude from cache'),
'#description' => t('Exclude this field from being cached. This will make sure your unencrypted data will not be exposed in the cache, but could have impact on your performance.'),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/could have impact/will have a negative impact/

@weitzman
Copy link

I haven't studied all the commits here, but I wonder why a field would decrypt during entity load. I would decrypyt at render time and mark the render array as max-age=0. That way we dont have to worry about entity cache, as it stores encrypted value.

@wimleers
Copy link

@weitzman Great idea. But I'm not entirely sure that's going to be possible. If field values are encrypted at all times except rendering, then I can imagine that anything relying on field data won't work correctly: Views, Rules …

This is also not how the module works currently, at least as far as I can tell based on https://raw.githubusercontent.com/d8-contrib-modules/field_encrypt/master/documentation/Field%20Encrypt%20Architecture.png.

I wish https://github.com/d8-contrib-modules/field_encrypt/blob/master/readme.md explained the architecture in detail, and especially the rationale for going with this approach. It's sparsely documented.

Which is alsow hy I had to ask #17 (comment) in the first place.

@nerdstein
Copy link
Contributor

@wimleers - I'm happy to elaborate on the architecture in greater detail if you can be more clear on gaps you have found. Do you want to know what hooks are being used? How we're storing things? Please share some of what you wish to see and I'll add it.

And, yes, any sort of metadata or data used in the processing of other entities (blocks, views, etc) will break if we only do rendering. In fact, we tried it.

@wimleers
Copy link

Great, could you document in the README then why you did not go that way? That'd help address concerns that anybody evaluating this module will have.

@wimleers
Copy link

@nerdstein And yes, it would be great if you could comprehensively document how this module deals with:

  • decrypting
  • encrypting
  • preventing decrypted information from being accessed and therefore leaked, especially by contrib/custom modules
  • related to prior point: which caveats to pay attention to as a contrib/custom module developer
  • how this module guarantees that decrypted content is NEVER cached, and why it must never be cached — or perhaps in which cases caching is allowed

i.e. any and all aspects affecting encryption, decryption and passing around decrypted data need to be documented. And actually… also how we're guaranteeing that the decryption keys are stored safely.

EDIT:
To clarify, I think such comprehensive documentation is crucial in a system as flexible as Drupal, where anybody can override anything on any level. Just one weak spot, and this module is rendered ineffective. That's why for a module like this, you need to have comprehensive (architecture) documentation and test coverage proving all expected weak spots are in fact protected.

@nerdstein
Copy link
Contributor

I will do so for the module as it is right now - but I'm very much open to adjusting the architecture if there is a better way to do this. That's precisely why we're asking for your contributions.

Our previous attempts to be more comprehensive with this may have been off, but it might not have been implemented correctly either.

If we have to make some architectural adjustments for this module - we should do it now.

@svendecabooter
Copy link
Contributor Author

@wimleers: I have updated the code based on your feedback to set the cache properties on the EntityType.

This works locally, but somehow the test case seems to cache the entity where it shouldn't. Still need to figure out why that assertion is failing exactly, as I can't reproduce it outside of the test.

@svendecabooter
Copy link
Contributor Author

In the latest commit I have taken an alternative approach to determine which entity types should be uncacheable. This seems to work better, and now the test cases are all passing.

Feedback welcome.

@@ -84,6 +88,19 @@ function field_encrypt_form_alter(&$form, FormStateInterface $form_state, $form_
],
);

// Add setting to decide if field should be excluded from cache.
$form['field_encrypt']['field_encrypt']['uncacheable'] = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

@nerdstein
Copy link
Contributor

Looks good to me! I'll be merging and i'll be doing extensive testing next week

@nerdstein nerdstein merged commit f5ea590 into d8-contrib-modules:master Apr 26, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants