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.