edge
เพิ่มเติมที่ rubyonrails.org: เพิ่มเติมเกี่ยวกับ Ruby on Rails

การเข้ารหัส Active Record

เอกสารนี้เป็นคู่มือในการเข้ารหัสข้อมูลฐานข้อมูลของคุณโดยใช้ Active Record

หลังจากอ่านเอกสารนี้คุณจะรู้:

Chapters

  1. ทำไมต้องเข้ารหัสข้อมูลระดับแอปพลิเคชัน?
  2. การใช้งานพื้นฐาน
  3. คุณสมบัติ
  4. การจัดการกุญแจ
  5. API
  6. การกำหนดค่า

Active Record สนับสนุนการเข้ารหัสระดับแอปพลิเคชัน มันทำงานโดยการประกาศว่าแอตทริบิวต์ใดควรถูกเข้ารหัสและการเข้ารหัสและถอดรหัสโดยอัตโนมัติเมื่อจำเป็น ชั้นการเข้ารหัสนั่นอยู่ระหว่างฐานข้อมูลและแอปพลิเคชัน แอปพลิเคชันจะเข้าถึงข้อมูลที่ไม่ได้เข้ารหัส แต่ฐานข้อมูลจะเก็บข้อมูลที่เข้ารหัสไว้

1 ทำไมต้องเข้ารหัสข้อมูลระดับแอปพลิเคชัน?

การเข้ารหัส Active Record มีไว้เพื่อป้องกันข้อมูลที่เป็นความลับในแอปพลิเคชันของคุณ ตัวอย่างที่สามารถพบได้บ่อยคือข้อมูลที่สามารถระบุตัวตนของผู้ใช้ แต่ทำไมคุณต้องการการเข้ารหัสระดับแอปพลิเคชันถ้าคุณกำลังเข้ารหัสฐานข้อมูลของคุณในสถานะพัก?

เป็นประโยชน์ที่เป็นปฏิทินทันทีการเข้ารหัสแอตทริบิวต์ที่เป็นความลับเพิ่มชั้นความปลอดภัยเพิ่มเติม ตัวอย่างเช่นหากผู้โจมตีเข้าถึงฐานข้อมูลของคุณ ภาพรวมของมัน หรือบันทึกแอปพลิเคชันของคุณ พวกเขาจะไม่สามารถทำความเข้าใจข้อมูลที่ถูกเข้ารหัสได้ นอกจากนี้การเข้ารหัสยังสามารถป้องกันนักพัฒนาไม่ให้เปิดเผยข้อมูลที่เป็นความลับของผู้ใช้ในบันทึกแอปพลิเคชันได้อีกด้วย

แต่สิ่งที่สำคัญกว่านั้น โดยใช้ Active Record Encryption คุณกำหนดว่าอะไรเป็นข้อมูลที่เป็นความลับในแอปพลิเคชันของคุณที่ระดับโค้ด Active Record Encryption ช่วยให้คุณควบคุมการเข้าถึงข้อมูลได้อย่างละเอียดในแอปพลิเคชันของคุณและบริการที่ใช้ข้อมูลจากแอปพลิเคชันของคุณ ตัวอย่างเช่นพิจารณา รถไฟเรลส์ที่ป้องกันข้อมูลที่เข้ารหัส หรือตรวจสอบระบบที่มีอยู่เพื่อ กรองพารามิเตอร์คอนโทรลเลอร์โดยอัตโนมัติ

2 การใช้งานพื้นฐาน

2.1 การตั้งค่า

ก่อนอื่นคุณต้องเพิ่มบางคีย์ใน ข้อมูลประจำตัวของ Rails ใช้คำสั่ง bin/rails db:encryption:init เพื่อสร้างคีย์เซ็ตที่สุ่ม:

$ bin/rails db:encryption:init
เพิ่มรายการนี้ในข้อมูลประจำตัวของสภาพแวดล้อมเป้าหมาย:

active_record_encryption:
  primary_key: EGY8WhulUOXixybod7ZWwMIL68R9o5kC
  deterministic_key: aPA5XyALhf75NNnMzaspW7akTfZp0lPY
  key_derivation_salt: xEY0dt6TZcAMg52K7O84wYzkjvbA62Hz

หมายเหตุ: ค่าที่สร้างขึ้นนี้มีความยาว 32 ไบต์ หากคุณสร้างขึ้นเองควรใช้ความยาวขั้นต่ำ 12 ไบต์สำหรับ primary key (นี่จะถูกใช้ในการได้รับคีย์ AES 32 ไบต์) และ 20 ไบต์สำหรับเกลือ

2.2 การประกาศแอตทริบิวต์ที่เข้ารหัส

แอตทริบิวต์ที่เข้ารหัสถูกกำหนดไว้ที่ระดับโมเดล นั่นคือแอตทริบิวต์ Active Record ปกติที่มีคอลัมน์ที่มีชื่อเดียวกัน

class Article < ApplicationRecord
  encrypts :title
end

ไลบรารีจะเข้ารหัสแอตทริบิวต์เหล่านี้โดยอัตโนมัติก่อนที่จะบันทึกลงในฐานข้อมูลและจะถอดรหัสเมื่อเรียกดู:

article = Article.create title: "Encrypt it all!"
article.title # => "Encrypt it all!"

แต่ในส่วนล่าง SQL ที่ทำงานดูเช่นนี้:

INSERT INTO `articles` (`title`) VALUES ('{\"p\":\"n7J0/ol+a7DRMeaE\",\"h\":{\"iv\":\"DXZMDWUKfp3bg/Yu\",\"at\":\"X1/YjMHbHD4talgF9dt61A==\"}}')

2.2.1 สำคัญ: เกี่ยวกับการจัดเก็บและขนาดคอลัมน์

การเข้ารหัสต้องการพื้นที่เพิ่มเติมเนื่องจากการเข้ารหัส Base64 และข้อมูลเมตาดาต้าที่เก็บไว้พร้อมกับเปลือกที่เข้ารหัส ในกรณีที่ใช้ผู้ให้บริการคีย์เข้ารหัสภายใน คุณสามารถประมาณการการเพิ่มขนาดที่แย่ที่สุดได้ประมาณ 255 ไบต์ การเพิ่มขนาดนี้เล็กน้อยในขนาดใหญ่ ไม่เพียงเพราะมันถูกแบ่งเป็นส่วน แต่เพราะไลบรารีใช้การบีบอัดโดยค่าเริ่มต้นซึ่งสามารถประหยัดพื้นที่จัดเก็บได้สูงสุดถึง 30% สำหรับข้อมูลที่ใหญ่กว่าเวอร์ชันที่ไม่ได้เข้ารหัส มีปัญหาสำคัญเกี่ยวกับขนาดคอลัมน์สตริง: ในฐานข้อมูลรุ่นใหม่ ขนาดคอลัมน์กำหนดจำนวนอักขระที่สามารถจัดสรรได้ ไม่ใช่จำนวนไบต์ ตัวอย่างเช่น ด้วย UTF-8 แต่ละอักขระสามารถใช้ได้สูงสุดถึงสี่ไบต์ ดังนั้น โดยหลักการ คอลัมน์ในฐานข้อมูลที่ใช้ UTF-8 สามารถเก็บข้อมูลได้สูงสุดถึงสี่เท่าของขนาดในเชิงจำนวนไบต์ ตอนนี้ ข้อมูลที่เข้ารหัสแล้วเป็นสตริงที่เป็นไบนารีที่ถูกแปลงเป็น Base64 ดังนั้น สามารถเก็บไว้ในคอลัมน์สตริงปกติได้ เนื่องจากเป็นลำดับของไบต์ ASCII คอลัมน์ที่ถูกเข้ารหัสอาจใช้พื้นที่สูงสุดถึงสี่เท่าของขนาดเวอร์ชันที่ชัดเจน ดังนั้น แม้ว่าไบต์ที่เก็บในฐานข้อมูลจะเหมือนกัน คอลัมน์จะต้องใหญ่ขึ้นถึงสี่เท่า

ในการปฏิบัติจริง นั่นหมายความว่า:

  • เมื่อเข้ารหัสข้อความสั้นที่เขียนด้วยอักขระตะวันตก (ส่วนมากเป็นอักขระ ASCII) คุณควรคำนึงถึงการเพิ่มพื้นที่เพิ่มเติม 255 เมื่อกำหนดขนาดคอลัมน์
  • เมื่อเข้ารหัสข้อความสั้นที่เขียนด้วยอักขระต่างประเทศ เช่น ซีริลลิก คุณควรคูณขนาดคอลัมน์ด้วย 4 โปรดทราบว่าการใช้พื้นที่เก็บข้อมูลเพิ่มเติมไม่เกิน 255 ไบต์
  • เมื่อเข้ารหัสข้อความยาว คุณสามารถละเว้นความกังวลเกี่ยวกับขนาดคอลัมน์ได้

ตัวอย่างบางส่วน:

เนื้อหาที่จะเข้ารหัส ขนาดคอลัมน์เดิม ขนาดคอลัมน์ที่แนะนำให้เข้ารหัส การเพิ่มพื้นที่เก็บ (กรณีที่แย่ที่สุด)
ที่อยู่อีเมล string(255) string(510) 255 ไบต์
ลำดับสั้นของอีโมจิ string(255) string(1020) 255 ไบต์
สรุปข้อความที่เขียนด้วยอักขระต่างประเทศ string(500) string(2000) 255 ไบต์
ข้อความยาวอย่างสมบูรณ์ text text ไม่สำคัญ

2.3 การเข้ารหัสแบบกำหนดเองและไม่กำหนดเอง

โดยค่าเริ่มต้น Active Record Encryption ใช้วิธีการเข้ารหัสแบบไม่กำหนดเอง แบบไม่กำหนดเองในที่นี้หมายความว่าการเข้ารหัสเนื้อหาเดียวกันด้วยรหัสผ่านเดียวกันสองครั้งจะได้รหัสข้อความที่แตกต่างกัน วิธีการนี้เพิ่มความปลอดภัยโดยทำให้การวิเคราะห์คริปโตของข้อความที่เข้ารหัสยากขึ้นและการค้นหาในฐานข้อมูลเป็นไปไม่ได้

คุณสามารถใช้ตัวเลือก deterministic: เพื่อสร้างเวกเตอร์เริ่มต้นในลักษณะที่กำหนดได้ ซึ่งจะเปิดใช้การค้นหาข้อมูลที่เข้ารหัสแล้วได้

class Author < ApplicationRecord
  encrypts :email, deterministic: true
end

Author.find_by_email("[email protected]") # คุณสามารถค้นหาโมเดลได้ตามปกติ

วิธีการที่ไม่กำหนดเองเป็นวิธีที่แนะนำ ยกเว้นว่าคุณต้องการค้นหาข้อมูล

หมายเหตุ: ในโหมดที่ไม่กำหนดเอง Active Record ใช้ AES-GCM ด้วยคีย์ 256 บิตและเวกเตอร์เริ่มต้นแบบสุ่ม ในโหมดที่กำหนดเอง มันยังใช้ AES-GCM แต่เวกเตอร์เริ่มต้นถูกสร้างเป็นการย่อย HMAC-SHA-256 ของคีย์และเนื้อหาที่จะเข้ารหัส

หมายเหตุ: คุณสามารถปิดใช้งานการเข้ารหัสแบบกำหนดเองได้โดยไม่ระบุ deterministic_key

3 คุณสมบัติ

3.1 Action Text

คุณสามารถเข้ารหัสแอตทริบิวต์ Action Text โดยการส่ง encrypted: true ในการประกาศของพวกเขา

class Message < ApplicationRecord
  has_rich_text :content, encrypted: true
end

หมายเหตุ: การส่งตัวเลือกการเข้ารหัสแบบรายบุคคลไปยังแอตทริบิวต์ Action Text ยังไม่ได้รับการสนับสนุน มันจะใช้การเข้ารหัสแบบไม่กำหนดเองด้วยตัวเลือกการเข้ารหัสทั่วไปที่กำหนด

3.2 ข้อมูลทดสอบ

คุณสามารถเข้ารหัสคุณสมบัติของ Rails โดยอัตโนมัติโดยเพิ่มตัวเลือกนี้ใน test.rb ของคุณ:

config.active_record.encryption.encrypt_fixtures = true

เมื่อเปิดใช้งาน แอตทริบิวต์ที่สามารถเข้ารหัสได้ทั้งหมดจะถูกเข้ารหัสตามการตั้งค่าการเข้ารหัสที่กำหนดในโมเดล

3.2.1 ข้อมูลการตั้งค่า Action Text Fixtures

ในการเข้ารหัส Action Text fixtures คุณควรวางไฟล์ไว้ที่ fixtures/action_text/encrypted_rich_texts.yml.

3.3 ประเภทที่รองรับ

active_record.encryption จะทำการซีเรียลไลซ์ค่าโดยใช้ประเภทใต้หลังคาก่อนที่จะทำการเข้ารหัส แต่ ต้องสามารถซีเรียลไลซ์เป็นสตรัคที่เป็นสตรัคได้ ประเภทที่มีโครงสร้างเช่น serialized สามารถรองรับได้โดยอัตโนมัติ

หากคุณต้องการรองรับประเภทที่กำหนดเอง วิธีที่แนะนำคือใช้ คุณสมบัติการซีเรียลไลซ์ การประกาศคุณสมบัติการซีเรียลไลซ์ควรอยู่ ก่อน การประกาศการเข้ารหัส:

# ถูกต้อง
class Article < ApplicationRecord
  serialize :title, type: Title
  encrypts :title
end

# ไม่ถูกต้อง
class Article < ApplicationRecord
  encrypts :title
  serialize :title, type: Title
end

3.4 การไม่สนใจตัวพิมพ์ใหญ่เล็ก

คุณอาจต้องการไม่สนใจตัวพิมพ์ใหญ่เล็กเมื่อค้นหาข้อมูลที่เข้ารหัสได้โดยแน่นอน มีวิธีที่ทำให้สามารถทำได้ง่ายดังนี้:

คุณสามารถใช้ตัวเลือก :downcase เมื่อประกาศคุณสมบัติการเข้ารหัสเพื่อทำให้เนื้อหาก่อนการเข้ารหัสเป็นตัวพิมพ์เล็กก่อนที่จะทำการเข้ารหัส:

class Person
  encrypts :email_address, deterministic: true, downcase: true
end

เมื่อใช้ :downcase ตัวพิมพ์เล็กจะหายไป ในบางสถานการณ์คุณอาจต้องการไม่สนใจตัวพิมพ์เล็กเท่านั้นเมื่อค้นหาในขณะที่ยังเก็บเนื้อหาต้นฉบับไว้ สำหรับสถานการณ์เช่นนั้นคุณสามารถใช้ตัวเลือก :ignore_case ซึ่งจะต้องเพิ่มคอลัมน์ใหม่ที่ชื่อว่า original_<column_name> เพื่อเก็บเนื้อหาโดยไม่เปลี่ยนแปลงตัวพิมพ์:

class Label
  encrypts :name, deterministic: true, ignore_case: true # เนื้อหาที่มีตัวพิมพ์ต้นฉบับจะถูกเก็บไว้ในคอลัมน์ `original_name`
end

3.5 การสนับสนุนข้อมูลที่ไม่ได้เข้ารหัส

เพื่อให้ง่ายต่อการย้ายข้อมูลที่ไม่ได้เข้ารหัส ไลบรารีรวมตัวเลือก config.active_record.encryption.support_unencrypted_data เมื่อตั้งค่าเป็น true:

  • การอ่านคุณสมบัติที่เข้ารหัสแล้วจะทำงานได้ตามปกติโดยไม่เกิดข้อผิดพลาดใด ๆ
  • การค้นหาด้วยคุณสมบัติที่เข้ารหัสแบบกำหนดไว้จะรวมเวอร์ชัน "ข้อความที่ชัดเจน" เพื่อรองรับการค้นหาเนื้อหาที่เข้ารหัสและที่ไม่ได้เข้ารหัส คุณต้องตั้งค่า config.active_record.encryption.extend_queries = true เพื่อเปิดใช้งานคุณสมบัตินี้

ตัวเลือกนี้ถูกออกแบบมาเพื่อใช้ในช่วงเวลาที่เปลี่ยนแปลง เมื่อข้อมูลที่ชัดเจนและข้อมูลที่เข้ารหัสต้องอยู่ร่วมกัน ทั้งสองตัวถูกตั้งค่าเป็น false เป็นค่าเริ่มต้น ซึ่งเป็นเป้าหมายที่แนะนำสำหรับแอปพลิเคชันใด ๆ: จะเกิดข้อผิดพลาดเมื่อทำงานกับข้อมูลที่ไม่ได้เข้ารหัส

3.6 การสนับสนุนระบบเข้ารหัสก่อนหน้านี้

การเปลี่ยนคุณสมบัติการเข้ารหัสของคุณสมบัติอาจทำให้ข้อมูลที่มีอยู่เสียหาย ตัวอย่างเช่น สมมุติว่าคุณต้องการทำให้คุณสมบัติที่กำหนดไว้แบบกำหนดไว้ไม่เป็นแบบกำหนดไว้ หากคุณเพียงแค่เปลี่ยนการประกาศในโมเดล การอ่านข้อความที่เข้ารหัสอยู่แล้วจะล้มเหลวเนื่องจากวิธีการเข้ารหัสไม่เหมือนกัน

เพื่อรองรับสถานการณ์เช่นนี้ คุณสามารถประกาศระบบเข้ารหัสก่อนหน้านี้ที่จะถูกใช้งานในสองสถานการณ์:

  • เมื่ออ่านข้อมูลที่เข้ารหัสแล้ว Active Record Encryption จะพยายามใช้ระบบเข้ารหัสก่อนหน้านี้หากระบบปัจจุบันไม่สามารถทำงานได้
  • เมื่อค้นหาข้อมูลที่เป็นข้อมูลแบบกำหนดไว้ Active Record Encryption จะเพิ่มข้อความที่เข้ารหัสก่อนหน้านี้เพื่อให้ค้นหาทำงานได้อย่างราบรื่นกับข้อมูลที่เข้ารหัสด้วยระบบที่แตกต่างกัน คุณต้องตั้งค่า config.active_record.encryption.extend_queries = true เพื่อเปิดใช้งานคุณสมบัตินี้

คุณสามารถกำหนดค่าระบบเข้ารหัสก่อนหน้านี้ได้:

  • ทั่วโลก
  • ตามแต่ละคุณสมบัติ

3.6.1 ระบบเข้ารหัสก่อนหน้านี้ทั่วโลก

คุณสามารถเพิ่มระบบเข้ารหัสก่อนหน้านี้ได้โดยเพิ่มเป็นรายการคุณสมบัติโดยใช้คุณสมบัติ previous ใน application.rb ของคุณ:

config.active_record.encryption.previous = [ { key_provider: MyOldKeyProvider.new } ]

3.6.2 ระบบการเข้ารหัสตามแต่ละคุณสมบัติ

ใช้ :previous เมื่อประกาศคุณสมบัติ:

class Article
  encrypts :title, deterministic: true, previous: { deterministic: false }
end

3.6.3 ระบบการเข้ารหัสและคุณสมบัติที่กำหนด

เมื่อเพิ่มระบบการเข้ารหัสก่อนหน้า:

  • ด้วยการเข้ารหัสที่ไม่กำหนดลำดับ, ข้อมูลใหม่จะถูกเข้ารหัสด้วยระบบการเข้ารหัสที่ใหม่ที่สุด (ปัจจุบัน) เสมอ
  • ด้วยการเข้ารหัสที่กำหนดลำดับ, ข้อมูลใหม่จะถูกเข้ารหัสด้วยระบบการเข้ารหัสที่เก่าที่สุด เป็นค่าเริ่มต้น

โดยทั่วไป, ในการเข้ารหัสที่กำหนดลำดับ, คุณต้องการให้ข้อความที่เข้ารหัสเหลือคงที่ คุณสามารถเปลี่ยนพฤติกรรมนี้ได้โดยการตั้งค่า deterministic: { fixed: false } ในกรณีนี้, จะใช้ระบบการเข้ารหัสที่ใหม่ที่สุด ในการเข้ารหัสข้อมูลใหม่

3.7 การจำกัดเงื่อนไขที่ไม่ซ้ำกัน

หมายเหตุ: การจำกัดเงื่อนไขที่ไม่ซ้ำกันสามารถใช้ได้เฉพาะกับข้อมูลที่เข้ารหัสด้วยระบบการเข้ารหัสที่กำหนดลำดับ

3.7.1 การตรวจสอบความไม่ซ้ำกัน

การตรวจสอบความไม่ซ้ำกันสามารถใช้ได้ตามปกติเมื่อเปิดใช้งานการค้นหาขยาย (config.active_record.encryption.extend_queries = true)

class Person
  validates :email_address, uniqueness: true
  encrypts :email_address, deterministic: true, downcase: true
end

การทำงานนี้ยังสามารถทำได้เมื่อผสมข้อมูลที่เข้ารหัสและข้อมูลที่ไม่เข้ารหัสรวมกัน และเมื่อกำหนดค่าระบบการเข้ารหัสก่อนหน้า

หมายเหตุ: หากคุณต้องการละเว้นตัวอักษรพิมพ์ใหญ่-เล็ก ตรวจสอบให้แน่ใจว่าใช้ downcase: หรือ ignore_case: ในการประกาศ encrypts การใช้ตัวเลือก case_sensitive: ในการตรวจสอบความไม่ซ้ำกันจะไม่ทำงาน

3.7.2 ดัชนีที่ไม่ซ้ำกัน

เพื่อรองรับดัชนีที่ไม่ซ้ำกันบนคอลัมน์ที่เข้ารหัสด้วยระบบการเข้ารหัสที่กำหนดลำดับ, คุณต้องให้แน่ใจว่าข้อความที่เข้ารหัสไม่เปลี่ยนแปลงเลย

เพื่อส่งเสริมการกระทำนี้, คุณสมบัติที่กำหนดลำดับจะใช้ระบบการเข้ารหัสที่เก่าที่สุดที่มีอยู่โดยค่าเริ่มต้นเมื่อกำหนดระบบการเข้ารหัสหลายระบบ มิฉะนั้น, คุณต้องรับผิดชอบในการให้คุณสมบัติการเข้ารหัสไม่เปลี่ยนแปลงสำหรับคุณสมบัติเหล่านี้ มิฉะนั้นดัชนีที่ไม่ซ้ำกันจะไม่ทำงาน

class Person
  encrypts :email_address, deterministic: true
end

3.8 การกรองพารามิเตอร์ที่มีชื่อเป็นคอลัมน์ที่เข้ารหัส

ตามค่าเริ่มต้น, คอลัมน์ที่เข้ารหัสจะถูกกำหนดค่าให้กรองโดยอัตโนมัติในบันทึกของ Rails คุณสามารถปิดการทำงานนี้ได้โดยเพิ่มส่วนต่อไปนี้ใน application.rb:

เมื่อสร้างพารามิเตอร์กรอง จะใช้ชื่อโมเดลเป็นคำนำหน้า เช่น: สำหรับ Person#name พารามิเตอร์กรองจะเป็น person.name

config.active_record.encryption.add_to_filter_parameters = false

ในกรณีที่คุณต้องการยกเว้นคอลัมน์ที่เฉพาะเจาะจงนี้จากการกรองอัตโนมัติ เพิ่มคอลัมน์เหล่านี้ใน config.active_record.encryption.excluded_from_filter_parameters

3.9 การเข้ารหัส

ไลบรารีจะเก็บรักษาการเข้ารหัสสำหรับค่าสตริงที่เข้ารหัสแบบไม่กำหนดลำดับ

เนื่องจากการเก็บรักษาการเข้ารหัสพร้อมกับข้อมูลที่เข้ารหัส, ค่าที่เข้ารหัสแบบกำหนดลำดับจะบังคับให้ใช้การเข้ารหัส UTF-8 เป็นค่าเริ่มต้น ดังนั้นค่าเดียวกันที่มีการเข้ารหัสแบบต่างกันจะได้รับการเข้ารหัสที่แตกต่างกัน คุณต้องการหลีกเลี่ยงสถานการณ์นี้เพื่อให้คำสั่งค้นหาและเงื่อนไขความไม่ซ้ำกันทำงาน ดังนั้นไลบรารีจะดำเนินการแปลงอัตโนมัติให้แทนคุณ

คุณสามารถกำหนดการเข้ารหัสเริ่มต้นที่ต้องการสำหรับการเข้ารหัสแบบกำหนดลำดับด้วย:

config.active_record.encryption.forced_encoding_for_deterministic_encryption = Encoding::US_ASCII

และคุณสามารถปิดการทำงานนี้และเก็บรักษาการเข้ารหัสในทุกกรณีด้วย:

config.active_record.encryption.forced_encoding_for_deterministic_encryption = nil

4 การจัดการกุญแจ

ผู้ให้บริการกุญแจจัดการกุญแจตามกลยุทธ์การจัดการกุญแจ คุณสามารถกำหนดค่าผู้ให้บริการกุญแจในระดับทั่วโลกหรือในระดับแต่ละคุณสมบัติ

4.1 ผู้ให้บริการกุญแจที่มีอยู่

4.1.1 DerivedSecretKeyProvider

ผู้ให้บริการกุญแจที่จะให้กุญแจที่ได้รับจากรหัสผ่านที่กำหนดให้โดยใช้ PBKDF2

config.active_record.encryption.key_provider = ActiveRecord::Encryption::DerivedSecretKeyProvider.new(["รหัสผ่านบางส่วน", "ที่จะใช้ในการได้รับกุญแจ", "เหล่านี้ควรอยู่ใน", "ข้อมูลประจำตัว"])

หมายเหตุ: โดยค่าเริ่มต้น, active_record.encryption กำหนดค่า DerivedSecretKeyProvider ด้วยกุญแจที่กำหนดไว้ใน active_record.encryption.primary_key

4.1.2 EnvelopeEncryptionKeyProvider

การสร้างคลาส EnvelopeEncryptionKeyProvider ที่มีการดำเนินการเข้ารหัสแบบซองอย่างง่าย:

  • สร้างคีย์สุ่มสำหรับแต่ละการเข้ารหัสข้อมูล
  • เก็บคีย์ข้อมูลพร้อมกับข้อมูลเองที่เข้ารหัสด้วยคีย์หลักที่กำหนดในข้อมูลประจำตัว active_record.encryption.primary_key.

คุณสามารถกำหนดค่า Active Record เพื่อใช้งานผู้ให้บริการคีย์นี้ได้โดยเพิ่มโค้ดนี้ใน application.rb:

config.active_record.encryption.key_provider = ActiveRecord::Encryption::EnvelopeEncryptionKeyProvider.new

เช่นเดียวกับผู้ให้บริการคีย์ที่มีอยู่อื่น ๆ คุณสามารถระบุรายการคีย์หลักใน active_record.encryption.primary_key เพื่อดำเนินการหมุนเวียนคีย์

4.2 ผู้ให้บริการคีย์ที่กำหนดเอง

สำหรับรูปแบบการจัดการคีย์ที่ซับซ้อนมากขึ้นคุณสามารถกำหนดค่าผู้ให้บริการคีย์ที่กำหนดเองในไฟล์ initializer:

ActiveRecord::Encryption.key_provider = MyKeyProvider.new

ผู้ให้บริการคีย์ต้องดำเนินการตามอินเตอร์เฟซนี้:

class MyKeyProvider
  def encryption_key
  end

  def decryption_keys(encrypted_message)
  end
end

ทั้งสองเมธอดนี้จะส่งกลับออบเจ็กต์ ActiveRecord::Encryption::Key:

  • encryption_key ส่งกลับคีย์ที่ใช้สำหรับการเข้ารหัสเนื้อหาบางส่วน
  • decryption keys ส่งกลับรายการคีย์ที่เป็นไปได้สำหรับการถอดรหัสข้อความที่กำหนด

คีย์สามารถรวมแท็กอะไรก็ได้ซึ่งจะถูกเก็บไว้โดยไม่เข้ารหัสกับข้อความ คุณสามารถใช้ ActiveRecord::Encryption::Message#headers เพื่อตรวจสอบค่าเหล่านั้นเมื่อถอดรหัส

4.3 ผู้ให้บริการคีย์สำหรับแต่ละโมเดล

คุณสามารถกำหนดค่าผู้ให้บริการคีย์สำหรับแต่ละคลาสด้วยตัวเลือก :key_provider:

class Article < ApplicationRecord
  encrypts :summary, key_provider: ArticleKeyProvider.new
end

4.4 คีย์สำหรับแต่ละโมเดล

คุณสามารถกำหนดคีย์ที่กำหนดให้กับคลาสที่กำหนดด้วยตัวเลือก :key:

class Article < ApplicationRecord
  encrypts :summary, key: "some secret key for article summaries"
end

Active Record ใช้คีย์เพื่อสร้างคีย์ที่ใช้สำหรับการเข้ารหัสและถอดรหัสข้อมูล

4.5 หมุนเวียนคีย์

active_record.encryption สามารถทำงานร่วมกับรายการคีย์เพื่อสนับสนุนการดำเนินการหมุนเวียนคีย์:

  • ใช้คีย์ล่าสุดสำหรับการเข้ารหัสเนื้อหาใหม่
  • ลองใช้คีย์ทั้งหมดเมื่อถอดรหัสเนื้อหาจนกว่าจะพบคีย์ที่ใช้ได้
active_record_encryption:
  primary_key:
    - a1cc4d7b9f420e40a337b9e68c5ecec6 # คีย์ก่อนหน้ายังสามารถถอดรหัสเนื้อหาที่มีอยู่ได้
    - bc17e7b413fd4720716a7633027f8cc4 # คีย์ที่ใช้งานอยู่ ใช้สำหรับการเข้ารหัสเนื้อหาใหม่
  key_derivation_salt: a3226b97b3b2f8372d1fc6d497a0c0d3

นี้ช่วยให้สามารถดำเนินการได้โดยใช้ขั้นตอนการเพิ่มคีย์ใหม่ เข้ารหัสเนื้อหาใหม่ และลบคีย์เก่า

หมายเหตุ: การหมุนเวียนคีย์ยังไม่รองรับการเข้ารหัสแบบกำหนดเอง

หมายเหตุ: Active Record Encryption ยังไม่มีการจัดการอัตโนมัติของกระบวนการหมุนเวียนคีย์ ส่วนประกอบทั้งหมดอยู่ที่นั่น แต่ยังไม่ได้รับการดำเนินการ

4.6 เก็บอ้างอิงคีย์

คุณสามารถกำหนดค่า active_record.encryption.store_key_references เพื่อให้ active_record.encryption เก็บอ้างอิงคีย์การเข้ารหัสในข้อความที่เข้ารหัสเอง

config.active_record.encryption.store_key_references = true

การทำเช่นนี้จะทำให้การถอดรหัสเร็วขึ้นเนื่องจากระบบสามารถค้นหาคีย์โดยตรงได้แทนที่จะลองใช้รายการคีย์ ราคาที่ต้องจ่ายคือการจัดเก็บ: ข้อมูลที่เข้ารหัสจะใหญ่ขึ้นเล็กน้อย

5 API

5.1 API พื้นฐาน

การเข้ารหัสของ ActiveRecord ถูกออกแบบให้ใช้งานแบบกำหนดเอง แต่มี API สำหรับสถานการณ์การใช้งานขั้นสูง

5.1.1 เข้ารหัสและถอดรหัส

article.encrypt # เข้ารหัสหรือเข้ารหัสใหม่สำหรับแอตทริบิวต์ที่สามารถเข้ารหัสได้ทั้งหมด
article.decrypt # ถอดรหัสทั้งหมดของแอตทริบิวต์ที่สามารถเข้ารหัสได้

5.1.2 อ่านข้อความที่เข้ารหัส

article.ciphertext_for(:title)

5.1.3 ตรวจสอบว่าแอตทริบิวต์ถูกเข้ารหัสหรือไม่

article.encrypted_attribute?(:title)

6 การกำหนดค่า

6.1 ตัวเลือกการกำหนดค่า

คุณสามารถกำหนดค่าตัวเลือก Active Record Encryption ใน application.rb (สถานการณ์ที่พบบ่อยที่สุด) หรือในไฟล์การกำหนดค่าสภาพแวดล้อมเฉพาะ config/environments/<env name>.rb หากคุณต้องการตั้งค่าเฉพาะสภาพแวดล้อม

คำเตือน: แนะนำให้ใช้การสนับสนุนของ Rails ในการเก็บคีย์ หากคุณต้องการตั้งค่าด้วยตนเองผ่านคุณสมบัติ config โปรดตรวจสอบให้แน่ใจว่าคุณไม่ได้เก็บรหัสไว้กับโค้ดของคุณ (เช่นใช้ตัวแปรสภาพแวดล้อม)

6.1.1 config.active_record.encryption.support_unencrypted_data

เมื่อเป็นจริง ข้อมูลที่ไม่ได้เข้ารหัสสามารถอ่านได้ตามปกติ หากเป็นเท็จ จะเกิดข้อผิดพลาด ค่าเริ่มต้น: false.

6.1.2 config.active_record.encryption.extend_queries

เมื่อเป็นจริง คำสั่งสอบถามที่อ้างอิงถึงแอตทริบิวต์ที่เข้ารหัสแบบกำหนดได้จะถูกแก้ไขเพื่อรวมค่าเพิ่มเติม (หากจำเป็น) ค่าเพิ่มเติมเหล่านี้จะเป็นเวอร์ชันที่สะอาดของค่า (เมื่อ config.active_record.encryption.support_unencrypted_data เป็นจริง) และค่าที่เข้ารหัสด้วยรูปแบบการเข้ารหัสก่อนหน้า (ตามที่ระบุในตัวเลือก previous:) ค่าเริ่มต้น: false (การทดลอง).

6.1.3 config.active_record.encryption.encrypt_fixtures

เมื่อเป็นจริง แอตทริบิวต์ที่เข้ารหัสได้ใน fixtures จะถูกเข้ารหัสโดยอัตโนมัติเมื่อโหลด ค่าเริ่มต้น: false.

6.1.4 config.active_record.encryption.store_key_references

เมื่อเป็นจริง การอ้างอิงถึงคีย์การเข้ารหัสจะถูกเก็บไว้ในส่วนหัวของข้อความที่เข้ารหัส สิ่งนี้ทำให้การถอดรหัสเร็วขึ้นเมื่อมีการใช้คีย์หลายตัว ค่าเริ่มต้น: false.

6.1.5 config.active_record.encryption.add_to_filter_parameters

เมื่อเป็นจริง ชื่อแอตทริบิวต์ที่เข้ารหัสจะถูกเพิ่มอัตโนมัติใน config.filter_parameters และจะไม่ปรากฏในบันทึก ค่าเริ่มต้น: true.

6.1.6 config.active_record.encryption.excluded_from_filter_parameters

คุณสามารถกำหนดค่ารายการ params ที่ไม่ต้องการให้ถูกกรองออกเมื่อ config.active_record.encryption.add_to_filter_parameters เป็นจริง ค่าเริ่มต้น: [].

6.1.7 config.active_record.encryption.validate_column_size

เพิ่มการตรวจสอบขึ้นอยู่กับขนาดคอลัมน์ แนะนำให้ใช้เพื่อป้องกันการเก็บข้อมูลขนาดใหญ่โดยใช้เปรียบเทียบข้อมูลที่บีบอัดได้สูงมาก ค่าเริ่มต้น: true.

6.1.8 config.active_record.encryption.primary_key

คีย์หรือรายการคีย์ที่ใช้ในการสร้างคีย์การเข้ารหัสข้อมูลราก วิธีการใช้ขึ้นอยู่กับผู้ให้บริการคีย์ที่กำหนดค่า แนะนำให้กำหนดค่าผ่านข้อมูลประจำตัว active_record_encryption.primary_key.

6.1.9 config.active_record.encryption.deterministic_key

คีย์หรือรายการคีย์ที่ใช้สำหรับการเข้ารหัสแบบกำหนดได้ แนะนำให้กำหนดค่าผ่านข้อมูลประจำตัว active_record_encryption.deterministic_key.

6.1.10 config.active_record.encryption.key_derivation_salt

เกลือที่ใช้ในการสร้างคีย์ แนะนำให้กำหนดค่าผ่านข้อมูลประจำตัว active_record_encryption.key_derivation_salt.

6.1.11 config.active_record.encryption.forced_encoding_for_deterministic_encryption

การเข้ารหัสเริ่มต้นสำหรับแอตทริบิวต์ที่เข้ารหัสแบบกำหนดได้ คุณสามารถปิดใช้งานการบังคับการเข้ารหัสโดยตั้งค่าตัวเลือกนี้เป็น nil ค่าเริ่มต้นคือ Encoding::UTF_8.

6.1.12 config.active_record.encryption.hash_digest_class

อัลกอริทึมการเข้ารหัสที่ใช้สร้างคีย์ OpenSSL::Digest::SHA1 เป็นค่าเริ่มต้น.

6.1.13 config.active_record.encryption.support_sha1_for_non_deterministic_encryption

รองรับการถอดรหัสข้อมูลที่เข้ารหัสแบบไม่กำหนดได้ด้วยคลาสการเข้ารหัส SHA1 ค่าเริ่มต้นเป็นเท็จ ซึ่งหมายความว่าจะรองรับเฉพาะอัลกอริทึมการเข้ารหัสที่กำหนดค่าใน config.active_record.encryption.hash_digest_class.

6.2 บริบทการเข้ารหัส

บริบทการเข้ารหัสกำหนดค่าส่วนประกอบการเข้ารหัสที่ใช้ในขณะที่กำลังใช้งาน มีบริบทการเข้ารหัสเริ่มต้นที่ขึ้นอยู่กับการกำหนดค่าทั่วโลกของคุณ แต่คุณสามารถกำหนดค่าบริบทที่กำหนดเองสำหรับแอตทริบิวต์ที่กำหนดหรือเมื่อเรียกใช้บล็อกโค้ดเฉพาะ

หมายเหตุ: บริบทการเข้ารหัสเป็นกลไกการกำหนดค่าที่ยืดหยุ่นแต่ซับซ้อน ผู้ใช้ส่วนใหญ่ไม่จำเป็นต้องสนใจถึงสิ่งเหล่านี้

ส่วนประกอบหลักของบริบทการเข้ารหัสคือ:

  • encryptor: เปิดเผย API ภายในสำหรับการเข้ารหัสและถอดรหัสข้อมูล มันจะปฏิสัมพันธ์กับ key_provider เพื่อสร้างข้อความที่เข้ารหัสและจัดการกับการตั้งค่าของพวกเขา การเข้ารหัส/ถอดรหัสเองจะทำโดย cipher และการตั้งค่าของ message_serializer.
  • cipher: อัลกอริทึมการเข้ารหัสเอง (AES 256 GCM)
  • key_provider: ให้บริการคีย์การเข้ารหัสและถอดรหัส
  • message_serializer: ทำการซีเรียลไลซ์และเอาออกข้อมูลที่เข้ารหัส (Message).

หมายเหตุ: หากคุณตัดสินใจสร้าง message_serializer เอง สิ่งสำคัญคือต้องใช้กลไกที่ปลอดภัยที่ไม่สามารถทำการเอาออกข้อมูลอย่างอิสระได้ สถานการณ์ที่รองรับทั่วไปคือการเข้ารหัสข้อมูลที่ไม่ได้เข้ารหัสอยู่แล้ว ผู้โจมตีสามารถใช้สิ่งนี้เพื่อใส่ข้อมูลที่ถูกแก้ไขก่อนการเข้ารหัสและดำเนินการโจมตี RCE นี่หมายความว่าซีเรียลไลเซอร์ที่กำหนดเองควรหลีกเลี่ยงการใช้ Marshal, YAML.load (ใช้ YAML.safe_load แทน), หรือ JSON.load (ใช้ JSON.parse แทน).

6.2.1 บริบทการเข้ารหัสระดับโลก

บริบทการเข้ารหัสระดับโลกเป็นบริบทที่ใช้โดยค่าเริ่มต้นและถูกกำหนดค่าเช่นเดียวกับคุณสมบัติการกำหนดค่าอื่น ๆ ใน application.rb หรือไฟล์การกำหนดค่าสภาพแวดล้อม

config.active_record.encryption.key_provider = ActiveRecord::Encryption::EnvelopeEncryptionKeyProvider.new
config.active_record.encryption.encryptor = MyEncryptor.new

6.2.2 บริบทการเข้ารหัสตามแต่ละแอตทริบิวต์

คุณสามารถแทนที่พารามิเตอร์ของบริบทการเข้ารหัสโดยการส่งผ่านในการประกาศแอตทริบิวต์:

class Attribute
  encrypts :title, encryptor: MyAttributeEncryptor.new
end

6.2.3 บริบทการเข้ารหัสเมื่อเรียกใช้บล็อกของโค้ด

คุณสามารถใช้ ActiveRecord::Encryption.with_encryption_context เพื่อตั้งค่าบริบทการเข้ารหัสสำหรับบล็อกของโค้ดที่กำหนด:

ActiveRecord::Encryption.with_encryption_context(encryptor: ActiveRecord::Encryption::NullEncryptor.new) do
  ...
end

6.2.4 บริบทการเข้ารหัสที่มีอยู่แบบภายใน

6.2.4.1 ปิดการเข้ารหัส

คุณสามารถเรียกใช้โค้ดโดยไม่มีการเข้ารหัส:

ActiveRecord::Encryption.without_encryption do
   ...
end

นี้หมายความว่าการอ่านข้อความที่ถูกเข้ารหัสจะคืนค่าข้อความที่ถูกเข้ารหัสและเนื้อหาที่บันทึกจะถูกเก็บไว้โดยไม่เข้ารหัส

6.2.4.2 ป้องกันข้อมูลที่ถูกเข้ารหัส

คุณสามารถเรียกใช้โค้ดโดยไม่มีการเข้ารหัสแต่ป้องกันการเขียนทับเนื้อหาที่ถูกเข้ารหัส:

ActiveRecord::Encryption.protecting_encrypted_data do
   ...
end

นี้จะเป็นประโยชน์หากคุณต้องการป้องกันข้อมูลที่ถูกเข้ารหัสในขณะที่ยังคงเรียกใช้โค้ดอย่างอิสระต่อมัน (เช่นใน Rails console)

ข้อเสนอแนะ

คุณสามารถช่วยปรับปรุงคุณภาพของคู่มือนี้ได้

กรุณาช่วยเพิ่มเติมหากพบข้อผิดพลาดหรือข้อผิดพลาดทางความจริง เพื่อเริ่มต้นคุณสามารถอ่านส่วน การสนับสนุนเอกสาร ของเราได้

คุณอาจพบเนื้อหาที่ไม่สมบูรณ์หรือเนื้อหาที่ไม่ได้อัปเดต กรุณาเพิ่มเอกสารที่ขาดหายไปสำหรับเนื้อหาหลัก โปรดตรวจสอบ Edge Guides ก่อนเพื่อตรวจสอบ ว่าปัญหาได้รับการแก้ไขหรือไม่ในสาขาหลัก ตรวจสอบ คู่มือแนวทาง Ruby on Rails เพื่อดูรูปแบบและกฎเกณฑ์

หากคุณพบข้อผิดพลาดแต่ไม่สามารถแก้ไขได้เอง กรุณา เปิดปัญหา.

และสุดท้าย การสนทนาใด ๆ เกี่ยวกับ Ruby on Rails เอกสารยินดีต้อนรับที่สุดใน เว็บบอร์ดอย่างเป็นทางการของ Ruby on Rails.