Rails 4 шифрует внешний ключ

Я создаю приложение, которое требует соответствия HIPAA, что означает, что я не могу допустить, чтобы определенные соединения были свободно доступны для просмотра в базе данных (пациенты и рекомендации для них).

Эти таблицы связаны через patients_recommendations таблица в моем приложении, которая работала хорошо, пока я не добавил шифрование через attr_encrypted. В попытке сократить объем шифрования и дешифрования (и связанные с этим издержки) я хотел бы иметь возможность просто зашифровать patient_id в patients_recommendations Таблица. Однако после изменения типа данных на string и имя столбца encrypted_patient_idприложение разрывается со следующей ошибкой при попытке повторного заполнения базы данных:

не может написать неизвестный атрибут `Patient_id'

Я предполагаю, что это потому, что объединение ищет столбец напрямую, а не просматривая модель (имеет смысл использовать модель, вероятно, медленнее). Есть ли способ, которым я могу заставить Rails пройти модель (где attr_encrypted добавил необходимые вспомогательные методы)?

Обновить:

В попытке найти обходной путь, я попытался добавить before_save к модели следующим образом:

before_save :encrypt_patient_id

...

private

def encrypt_patient_id
  self.encrypted_patient_id = PatientRecommendation.encrypt(:patient_id, self.patient_id)
  self.patient_id = nil
end

Это также не работает, что приводит к той же ошибке unknown attribute, Любое решение будет работать для меня (хотя первое будет касаться основной проблемы), любые идеи, почему before_save не вызывается при создании через ассоциацию?

2 ответа

Решение

Вероятно, вам следует хранить данные PII и данные PHI в отдельных БД. Зашифруйте данные PII (включая любые связи с поставщиком или местоположением поставщика), а затем хэшируйте все данные PHI, чтобы упростить их. Пока нет прямой связи между ними, было бы приемлемо не шифровать данные PHI, поскольку они анонимны.

План А

Не установлен patient_id в nil в encrypt_patient_id поскольку его не существует и проблема может уйти.

Кроме того, завершение обратного вызова с nil или же false остановит цепочку обратного вызова, выставит объяснение true в конце метода.

План Б, переосмыслить ваши варианты

Существуют и другие варианты - от прозрачного шифрования на уровне базы данных (которое формально шифрует данные на диске) до зашифрованных файловых систем для хранения определенных табличных пространств и выравнивания шифрования данных в столбцах.

Шифрование столбцов соединения звучит как дорога к несчастью по разным причинам - от проблем с отчетами до проблем производительности, когда необходимо объединение, которое может быть довольно серьезным,

проблема, которую вы сейчас испытываете с начальным числом, выглядит так, как будто это первый удар, вызванный этим на плохой дороге (в этом случае activerecord, похоже, не понимает, как справиться с вашей ассоциацией, он пытается установить patient_id на инициализацию и разрывы).

Затраты на шифрование данных с ограничениями могут быть не такими высокими, как вы думаете, не зная, как обстоят дела с HIPAA, но для PCI вам точно не рекомендуется отображать защищенные данные на экране, поэтому шифрование сопряжено с небольшими накладными расходами, поскольку это происходит относительно редко. (бизнес-нужно знать и т. д.).

Кроме того, память, вероятно, считается "не в состоянии покоя и не в пути", теоретически вы можете кэшировать некоторые чистые значения в течение ограниченных периодов времени и, таким образом, сэкономить на издержках дешифрования.

По сути, шифрование данных может быть не таким уж плохим, а шифрование ключей в базе данных может быть хуже, чем вы думаете

Я предлагаю поговорить напрямую, я занимаюсь вопросами соответствия PCI DSS, и эта тема меня интересует.

Опция: односторонние хеши для первичных / внешних ключей

PatientRecommendation будет иметь хэш patient_id - назови это patient_hash а также Patient будет способен генерировать то же самое patient_hash от его id - но я бы посоветовал хранить patient_hash в обеих таблицах, для Patient это был бы первичный ключ для соединения и для PatientRecommendation это был бы внешний ключ для соединения,

таким образом, вы определяете отношение рельсов в этих терминах, и рельсы больше не будут путать вашу схему отношений

has_many :patient_recommendations, primary_key: :patient_hash, foreign_key: :patient_hash

и результат криптографически более надежен и прост для обработки базы данных

ЕСЛИ ты непреклонен в том, чтобы не хранить patient_hash в Patient Вы можете использовать простой SQL-оператор, чтобы сделать отношение - менее удобное, но работоспособное - что-то в строках этого псевдосклика:

JOIN ON generate_hash(patient.id) = patient_recommendations.patient_hash

Oracle, например, имеет возможность создавать функциональные индексы (думаю, create index generate_hash(patient.id)), поэтому этот подход может быть довольно эффективным в зависимости от вашего выбора базы данных.

Тем не менее, игра с клавишами соединения значительно усложнит вашу жизнь, даже с этими мерами


Я расскажу об этом посте позже с дополнительными опциями

Другие вопросы по тегам