การปฏิบัติที่ดีที่สุดสำหรับการจัดการกับรหัสผ่านในที่เก็บคอมไพล์คืออะไร?


225

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

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

คำตอบ:


256

วิธีทั่วไปในการทำเช่นนี้คือการอ่านข้อมูลรหัสผ่านจากไฟล์กำหนดค่า หากไฟล์การกำหนดค่าของคุณถูกเรียกfoobar.configแล้วคุณจะยอมรับไฟล์ที่เรียกว่าfoobar.config.exampleไปยังพื้นที่เก็บข้อมูลที่มีข้อมูลตัวอย่าง ในการเรียกใช้โปรแกรมของคุณคุณจะต้องสร้างไฟล์ท้องถิ่น (ไม่ได้ติดตาม) ที่เรียกว่าfoobar.configด้วยข้อมูลรหัสผ่านจริงของคุณ

เพื่อกรองรหัสผ่านที่มีอยู่ของคุณจากการกระทำก่อนหน้านี้ดูที่หน้าช่วยเหลือ GitHub ในการลบข้อมูลที่สำคัญ


4
Btw คุณสามารถเพิ่มตัวอย่าง foobar.config ไปยัง repo แล้วเพิ่ม foobar.config ไปยังไฟล์. signore วิธีนี้ตัวอย่าง foobar.config จะปรากฏขึ้นเมื่อโคลนและรหัสผ่านจริงของคุณจะไม่ถูกเพิ่มลงใน repo
Mr_Chimp

16
@Mr_Chimp: .gitignoreไฟล์ใช้ไม่ได้กับไฟล์ที่ถูกติดตามที่มีอยู่แล้วในที่เก็บ ยกตัวอย่างเช่นจะเพิ่มไฟล์การเปลี่ยนแปลงแม้ว่าจะมีอยู่แล้วในgit add -u .gitignore
เกร็กฮิวกิลล์

1
นี่คือลิงค์ที่น่าสนใจในกรณีที่คุณเพิ่มไฟล์กำหนดค่าโดยไม่ตั้งใจและคุณต้องการลบออกจากประวัติ git: help.github.com/articles/remove-sensitive-data
Loïc Lopes

16
คุณจะแบ่งปันรหัสผ่านเหล่านั้นกับทีมของคุณอย่างไร สิ่งหนึ่งคือการมีสำเนาในเครื่อง (ไม่ได้ทำสัญญากับ repo) อีกอย่างคือการแบ่งปันกับทีมที่ใหญ่กว่าด้วยเครื่องมืออัตโนมัติ (สำหรับการใช้งาน ฯลฯ )
blueFast

2
ฉันมีคำถามเดียวกันกับ @dangonfast ดูเหมือนจะไม่เป็นประโยชน์สำหรับทีมขนาดใหญ่
Jacob Stamm

25

วิธีการสามารถตั้งรหัสผ่าน (หรือคีย์ API) โดยใช้ตัวแปรสภาพแวดล้อม รหัสผ่านนี้จึงไม่สามารถแก้ไขได้

ด้วย Bash คุณสามารถตั้งค่าตัวแปรสภาพแวดล้อมได้โดยใช้

export your_env_variable='your_password'

วิธีการนี้สามารถใช้กับบริการการรวมอย่างต่อเนื่องเช่นTravisรหัสของคุณ (ไม่มีรหัสผ่าน) ถูกเก็บไว้ในGitHubเก็บสามารถดำเนินการได้โดย Travis (ด้วยรหัสผ่านของคุณที่ตั้งค่าไว้โดยใช้ตัวแปรสภาพแวดล้อม)

ด้วย Bash คุณสามารถรับค่าของตัวแปรสภาพแวดล้อมได้โดยใช้:

echo "$your_env_variable"

ด้วย Python คุณสามารถรับค่าของตัวแปรสภาพแวดล้อมได้โดยใช้:

import os
print(os.environ['your_env_variable'])

PS: โปรดทราบว่าอาจเป็นความเสี่ยงเล็กน้อย (แต่เป็นวิธีปฏิบัติทั่วไป) https://www.bleepingcomputer.com/news/security/javascript-packages-caught-stealing-environment-variables/

PS2: dev.toบทความนี้มีชื่อว่า"วิธีจัดเก็บคีย์ API อย่างปลอดภัย"อาจน่าสนใจในการอ่าน


1
วิธีการป้องกันการสร้างรหัสที่ไม่ปลอดภัยที่อาจเกิดขึ้นจากการอ่านเนื้อหาของตัวแปรสภาพแวดล้อมของคุณเป็นอย่างไร
gorootde

ฉันขอแนะนำให้มีลักษณะที่blog.travis-ci.com/2013-06-10-secure-env-in-pull-requestsและdocs.travis-ci.com/user/pull-requests/...
scls

16

สิ่งที่เกร็กกล่าวว่าfoobar.config-TEMPLATEแต่ฉันต้องการเพิ่มว่ามันเป็นความคิดที่ดีที่จะตรวจสอบในแฟ้ม

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

บ่อยครั้งที่ค่าการกำหนดค่าอาจไม่ชัดเจนเช่นสตริงการเชื่อมต่อฐานข้อมูลและสิ่งที่คล้ายกัน


7

การจัดการกับรหัสผ่านในที่เก็บข้อมูลจะได้รับการจัดการด้วยวิธีที่แตกต่างกันไปขึ้นอยู่กับปัญหาที่แท้จริงของคุณ

1. อย่าทำ

และวิธีที่จะหลีกเลี่ยงการทำนั้นครอบคลุมในการตอบกลับบางอย่าง - .gitignore, config.example, ฯลฯ

  • .gitignore: เก็บไว้ในเซิร์ฟเวอร์และอื่น ๆ แต่ไม่ใช่ Git (โซลูชันอ่อน)
  • ตัวแปรสภาพแวดล้อม: https://stackoverflow.com/a/30664318/3070485
  • กำหนดค่าตัวอย่าง: https://stackoverflow.com/a/2397905/3070485
  • พารามิเตอร์บรรทัดคำสั่ง: ป้อนรหัสผ่านด้วยตนเองเมื่อเริ่มต้นโปรแกรม

หรือ 2. ทำให้พื้นที่เก็บข้อมูลเข้าถึงได้เฉพาะผู้ที่ได้รับอนุญาตเท่านั้น

นั่นคือคนที่ได้รับอนุญาตให้รู้รหัสผ่าน chmodและกลุ่มผู้ใช้อยู่ในใจ นอกจากนี้ปัญหาเช่น Github หรือพนักงาน AWS ควรได้รับอนุญาตให้ดูสิ่งต่าง ๆ ถ้าคุณโฮสต์ที่เก็บหรือเซิร์ฟเวอร์ของคุณจากภายนอก?

หรือ 3. เข้ารหัสข้อมูลที่ละเอียดอ่อน (วัตถุประสงค์ของการตอบกลับนี้)

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

ตัวอย่างโซลูชัน Javascript ที่ใช้ข้อมูลการกำหนดค่าที่เข้ารหัสแสดงไว้ด้านล่าง

const fs = require('fs');
const NodeRSA = require('node-rsa');

let privatekey = new NodeRSA();
privatekey.importKey(fs.readFileSync('private.key', 'utf8'));
const config = privatekey.decrypt(fs.readFileSync('config.RSA', 'utf8'), 'json');

console.log('decrypted: ', config);

ถอดรหัสไฟล์กำหนดค่า

ดังนั้นคุณสามารถกู้คืนไฟล์กำหนดค่าที่เข้ารหัสซึ่งเขียน Javascript เพียงไม่กี่บรรทัด

โปรดทราบว่าการวางไฟล์config.RSAลงในที่เก็บ git จะทำให้มันเป็นไฟล์ไบนารีได้อย่างมีประสิทธิภาพและดังนั้นมันจะสูญเสียประโยชน์หลายอย่างของ Git เช่นความสามารถในการเลือกการเปลี่ยนแปลงของเชอร์รี่

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

ตัวอย่างของฉันด้านบนนั้นไม่มีประโยชน์อะไรสำหรับทุกคนที่ต้องการทำการทดสอบหรือเป็นตัวอย่างที่จะเริ่มต้นจากมันจะถือว่ามีคีย์ RSA และไฟล์ config ที่เข้ารหัสconfig.RSAไว้

ดังนั้นนี่คือโค้ดเพิ่มเติมบางบรรทัดที่เพิ่มเข้ามาเพื่อสร้างคีย์ RSA และไฟล์กำหนดค่าที่จะเล่น

const fs = require('fs');
const NodeRSA = require('node-rsa');

/////////////////////////////
// Generate some keys for testing
/////////////////////////////

const examplekey = new NodeRSA({b: 2048});

fs.writeFileSync('private.key', examplekey.exportKey('pkcs8-private'));
fs.writeFileSync('public.key', examplekey.exportKey('pkcs8-public'));

/////////////////////////////
// Do this on the Machine creating the config file
/////////////////////////////

const configToStore = {Goodbye: 'Cruel world'};

let publickey = new NodeRSA();
publickey.importKey(fs.readFileSync('public.key', 'utf8'));

fs.writeFileSync('config.RSA', publickey.encrypt(configToStore, 'base64'), 'utf8');

/////////////////////////////
// Do this on the Machine consuming the config file
/////////////////////////////

let privatekey = new NodeRSA();
privatekey.importKey(fs.readFileSync('private.key', 'utf8'));

const config = privatekey.decrypt(fs.readFileSync('config.RSA', 'utf8'), 'json');
console.log('decrypted: ', config);

การเข้ารหัสค่าเท่านั้น

fs.writeFileSync('config.RSA', JSON.stringify(config,null,2), 'utf8');

ป้อนคำอธิบายรูปภาพที่นี่

คุณสามารถถอดรหัสไฟล์กำหนดค่าด้วยค่าที่เข้ารหัสโดยใช้สิ่งนี้

const savedconfig = JSON.parse(fs.readFileSync('config.RSA', 'utf8'));
let config = {...savedconfig};
Object.keys(savedconfig).forEach(key => {
    config[key] = privatekey.decrypt(savedconfig[key], 'utf8');
});

ด้วยแต่ละรายการการกำหนดค่าในบรรทัดแยกต่างหาก (เช่นHelloและGoodbyeสูงกว่า) Git จะจดจำสิ่งที่เกิดขึ้นในไฟล์ได้ดีขึ้นและจะเก็บการเปลี่ยนแปลงรายการข้อมูลเป็นความแตกต่างแทนที่จะเป็นไฟล์ที่สมบูรณ์ Git จะสามารถจัดการการผสานและการหยิบเชอร์รี่ได้ดีขึ้น

อย่างไรก็ตามยิ่งคุณต้องการควบคุมการเปลี่ยนแปลงข้อมูลที่ละเอียดอ่อนมากเท่าไหร่ยิ่งคุณย้ายไปยังโซลูชัน SAFE REPOSITORY (2) และอยู่ห่างจากโซลูชันเข้ารหัสข้อมูล (3)


3

หนึ่งสามารถใช้Vaultที่รักษาความปลอดภัยจัดเก็บและควบคุมการเข้าถึงโทเค็นรหัสผ่านใบรับรองคีย์ API และอื่น ๆ ตัวอย่างเช่นAnsibleใช้Ansible Vaultซึ่งเกี่ยวข้องกับรหัสผ่านหรือใบรับรองที่ใช้ใน playbooks


ฉันพบว่า Ansible Vault นั้นซับซ้อนเกินไปเมื่อเทียบกับเพียงแค่สร้างไฟล์กำหนดค่าตัวอย่าง
icc97

@ icc97 ใช่มันน่าเศร้าจริง แต่เราต้องพูดถึงความเป็นไปได้นี้ ในความคิดของฉันสำหรับงานที่ซับซ้อนมากขึ้นแล้วการจัดเก็บรหัสผ่านไม่กี่สภาพแวดล้อมสำหรับผู้ใช้คนเดียวดีกว่าที่จะใช้โซลูชั่นพิเศษตั้งแต่ต้น
El Ruso

2
เพื่อช่วยผู้อ่านในอนาคต: Vault และ Ansible Vault เป็นโครงการที่ไม่เกี่ยวข้องกับชื่อที่คล้ายกันมาก
bltavares

2

นี่คือเทคนิคที่ฉันใช้:

ฉันสร้างโฟลเดอร์ในโฟลเดอร์บ้านของฉันชื่อ: .config

ในโฟลเดอร์นั้นฉันวางไฟล์ปรับแต่งสำหรับสิ่งต่าง ๆ ที่ฉันต้องการส่งออกรหัสผ่านและกุญแจ

ฉันมักจะใช้ไวยากรณ์ชื่อโดเมนกลับเช่น:

com.example.databaseconfig

จากนั้นในสคริปต์ทุบตีฉันทำสิ่งนี้:

#!/bin/bash
source $HOME/.config/com.example.databaseconfig ||exit 1

|| exit 1ทำให้เกิดสคริปต์เพื่อออกถ้ามันไม่สามารถที่จะโหลดไฟล์ config

ฉันใช้เทคนิคนั้นสำหรับทุบตีงูหลามและสคริปต์มด

ฉันเป็นคนหวาดระแวงและไม่คิดว่าไฟล์. gitignore มีประสิทธิภาพเพียงพอที่จะป้องกันการเช็คอินโดยไม่ได้ตั้งใจ นอกจากนี้ยังไม่มีการตรวจสอบใด ๆ ดังนั้นหากมีการเช็คอินเกิดขึ้นจะไม่มีใครสามารถจัดการกับมันได้

หากแอปพลิเคชั่นหนึ่งต้องการไฟล์มากกว่าหนึ่งไฟล์ฉันจะสร้างโฟลเดอร์ย่อยแทนไฟล์เดียว


1

หากคุณใช้ทับทิมบนรางอัญมณี Figaro นั้นดีมากง่ายและน่าเชื่อถือ มันมีปัจจัยปวดหัวต่ำกับสภาพแวดล้อมการผลิตด้วย


4
คุณสามารถให้รายละเอียดเกี่ยวกับสิ่งที่อัญมณีนั้นทำ? ด้วยวิธีนี้ (อาจ) ถือได้ว่าเป็น 'การปฏิบัติ' ที่ใช้งานได้ในหลายภาษา
mattumotu

medium.com/@MinimalGhost/ ......มีภาพรวมโดยทั่วไปดูเหมือนว่าจะจัดการการดึงสิ่งต่าง ๆ จากไฟล์กำหนดค่า
triple

0

เชื่อ แต่ยืนยัน

ในกรณี.gitignoreนี้จะยกเว้นไดเรกทอรี "ปลอดภัย" จาก repo:

secure/

แต่ฉันแบ่งปันความหวาดระแวงของ @Michael Potter ดังนั้นเพื่อตรวจสอบ. gignignore ต่อไปนี้เป็นการทดสอบหน่วยPython ที่จะเพิ่ม klaxon หากไดเรกทอรี "ปลอดภัย" นี้เคยได้รับการเช็คอินและเพื่อตรวจสอบการตรวจสอบไดเรกทอรีที่ถูกต้องจะถูกทดสอบด้วย:

def test_github_not_getting_credentials(self):
    safety_url = 'https://github.com/BobStein/fliki/tree/master/static'
    danger_url = 'https://github.com/BobStein/fliki/tree/master/secure'

    self.assertEqual(200, urllib.request.urlopen(safety_url).status)

    with self.assertRaises(urllib.error.HTTPError):
        urllib.request.urlopen(danger_url)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.