วิธีรักษาความปลอดภัยพอร์ต PostgreSQL ที่เปิดอยู่


29

ดังนั้นนี่คือสถานการณ์ ดูเหมือนว่าเราจำเป็นต้องมีพอร์ต TCP แบบเปิด 5432 ไปทั่วโลกซึ่งลูกค้าสามารถเข้าถึงฐานข้อมูล PostgreSQL ของเขาได้

ด้วยเหตุผลที่ชัดเจนเราไม่สามารถพูดได้ว่า "ไม่" เป็นทางเลือกสุดท้ายเท่านั้น

อะไรคือปัญหาที่ใหญ่ที่สุด? ฉันจะปกป้องโครงสร้างพื้นฐานของเราได้อย่างไร

ยังไงก็ตาม: ทำไมมันถึงไม่ควรเปิดให้คนทั่วโลกเห็น? ฉันคิดว่าบางทีมันอาจจะปลอดภัยกว่าเซิร์ฟเวอร์ FTP เก่า ๆ ที่อายุ 20 ปี

PS VPN ไม่เป็นไร บางเข้ารหัสอาจ (ถ้าฉันสามารถให้เขา URL ที่เชื่อมต่อ JDBC ที่ทำงาน )


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

@LuciferSam ไม่ใช่ db จะถูกใช้โดยแอปพลิเคชัน java ที่พัฒนาภายใน บริษัท บนเครื่องของ บริษัท กว่า 100 เครื่อง วิธีเดียวของเราในการกำหนดค่าคือการให้การเชื่อมต่อ jdbc url กับการจัดการ localnet ของพวกเขาอื่น ๆ มีปัญหามาก

@milkman แอปทำอะไรได้บ้าง บางทีมันสามารถสืบค้นเซิร์ฟเวอร์ RESTful แทนได้หรือไม่ เห็นได้ชัดว่าผ่าน SQL กับส่วนที่เหลือไม่ได้รับอะไร แต่สมมติว่ามันเป็น CRUD ..
tedder42

@ tedder42 มันจัดการฐานข้อมูลของผู้ใช้ CMS ซึ่งโฮสต์โดยเราเช่นกัน เราไม่ได้รับอนุญาตให้เปลี่ยนแหล่งที่มา

คำตอบ:


41

ต้องใช้ SSL ให้ SELinux เปิดการตรวจสอบการบันทึกและใช้รุ่น PostgreSQL ปัจจุบัน

ฝั่งเซิร์ฟเวอร์

ต้องการ SSL

ในการpostgresql.confตั้งค่าssl=onและให้แน่ใจว่าคุณมีการติดตั้ง keyfile และ certfile ของคุณอย่างเหมาะสม (ดูเอกสารและความคิดเห็นในpostgresql.conf)

คุณอาจจำเป็นต้องซื้อใบรับรองจาก CA หากคุณต้องการให้ลูกค้าเชื่อถือโดยไม่ต้องมีการตั้งค่าพิเศษในไคลเอนต์

ในการpg_hba.confใช้งานสิ่งที่ชอบ:

hostssl theuser thedatabase 1.2.3.4/32 md5

... อาจมี "ทั้งหมด" สำหรับผู้ใช้และ / หรือฐานข้อมูลและอาจมีตัวกรองที่อยู่ IP ของแหล่งข้อมูลที่กว้างขึ้น

จำกัด ผู้ใช้ที่สามารถเข้าสู่ระบบปฏิเสธการล็อกอิน superuser ระยะไกล

ไม่อนุญาตผู้ใช้ "ทั้งหมด" สำหรับผู้ใช้ถ้าเป็นไปได้; คุณไม่ต้องการอนุญาตการล็อกอิน superuser จากระยะไกลหากคุณสามารถหลีกเลี่ยงความต้องการนี้ได้

จำกัด สิทธิ์ของผู้ใช้

จำกัด สิทธิ์ของผู้ใช้ที่สามารถเข้าสู่ระบบห้ามให้สิทธิ์CREATEDBหรือCREATEUSERสิทธิ์แก่พวกเขา

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

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

การตั้งค่าไคลเอนต์

ใน PgJDBC ให้ส่งพารามิเตอร์ssl=true :

หากต้องการแนะนำให้ไดรเวอร์ JDBC ลองและสร้างการเชื่อมต่อ SSL คุณต้องเพิ่มพารามิเตอร์ URL การเชื่อมต่อ ssl = true

... และติดตั้งใบรับรองเซิร์ฟเวอร์ใน truststore ของไคลเอ็นต์หรือใช้ใบรับรองเซิร์ฟเวอร์ที่เชื่อถือได้โดยหนึ่งใน CAs ใน truststore ในตัวของ Java หากคุณไม่ต้องการให้ผู้ใช้ต้องติดตั้งใบรับรอง

การกระทำอย่างต่อเนื่อง

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

เพิ่มไฟร์วอลล์ไว้ด้านหน้าถ้ามี netblocks / พื้นที่ขนาดใหญ่ที่คุณรู้ว่าคุณไม่จำเป็นต้องเข้าถึง

บันทึกการเชื่อมต่อและการยกเลิกการเชื่อมต่อ (ดูpostgresql.conf) บันทึกคำค้นหาถ้าใช้งานได้จริง เรียกใช้ระบบตรวจจับการบุกรุกหรือ fail2ban หรือคล้ายกันถ้าใช้งานได้จริง สำหรับ fail2ban ที่มี postgres จะมีวิธีใช้ที่สะดวกที่นี่

ตรวจสอบไฟล์บันทึก

ความหวาดระแวงโบนัส

ขั้นตอนเพิ่มเติมที่ต้องคำนึงถึง ...

ต้องใช้ใบรับรองไคลเอ็นต์

หากคุณต้องการคุณยังสามารถใช้pg_hba.confเพื่อกำหนดให้ไคลเอ็นต์แสดงใบรับรองไคลเอ็นต์ X.509 ที่เซิร์ฟเวอร์เชื่อถือได้ ไม่จำเป็นต้องใช้ CA เดียวกับใบรับรองเซิร์ฟเวอร์คุณสามารถทำได้ด้วย homebrew openssl CA ผู้ใช้ JDBC ต้องอิมพอร์ตใบรับรองไคลเอ็นต์keytoolไปยัง Java Keystore ด้วยและอาจกำหนดค่าคุณสมบัติระบบ JSSE บางอย่างเพื่อชี้ Java เป็นที่เก็บคีย์ดังนั้นจึงไม่โปร่งใสโดยสิ้นเชิง

กักกันอินสแตนซ์

หากคุณต้องการที่จะหวาดระแวงจริงๆให้เรียกใช้อินสแตนซ์สำหรับลูกค้าใน container / VM แยกต่างหากหรืออย่างน้อยก็ภายใต้บัญชีผู้ใช้อื่นโดยมีเพียงฐานข้อมูลที่พวกเขาต้องการ

ด้วยวิธีนี้หากพวกเขาประนีประนอมอินสแตนซ์ PostgreSQL พวกเขาจะไม่ได้รับอีกต่อไป

ใช้ SELinux

ฉันไม่ควรจะพูดแบบนี้ แต่ ...

เรียกใช้เครื่องที่มีการสนับสนุน SELinux เช่น RHEL 6 หรือ 7 และไม่ได้เปิด SELinux ปิดหรือตั้งค่าให้โหมดอนุญาต เก็บไว้ในโหมดบังคับใช้

ใช้พอร์ตที่ไม่ใช่ค่าเริ่มต้น

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

เรียกใช้ Pg บนพอร์ตที่ไม่ใช่ค่าเริ่มต้นเพื่อทำให้ชีวิตยากขึ้นสำหรับผู้โจมตีอัตโนมัติ

วางพร็อกซีไว้ด้านหน้า

คุณยังสามารถเรียกใช้ PgBouncer หรือ PgPool-II หน้า PostgreSQL ซึ่งทำหน้าที่เป็นพูลการเชื่อมต่อและพร็อกซี ด้วยวิธีนี้คุณสามารถอนุญาตให้พร็อกซีจัดการ SSL ไม่ใช่โฮสต์ฐานข้อมูลจริง พร็อกซีสามารถอยู่บน VM หรือเครื่องแยกต่างหาก

การใช้พร็อกซีการรวมการเชื่อมต่อโดยทั่วไปแล้วเป็นความคิดที่ดีสำหรับ PostgreSQL อยู่แล้วยกเว้นว่าแอปไคลเอนต์มีพูลในตัวอยู่แล้ว เซิร์ฟเวอร์แอปพลิเคชัน Java ส่วนใหญ่ Rails ฯลฯ มีการรวมกำไรในตัว แม้กระนั้นพร็อกซีพูรวมฝั่งเซิร์ฟเวอร์ก็ยังไม่เป็นอันตรายที่สุด


3
หากไคลเอนต์มี IP แบบสแตติก $ อนุญาตให้ผ่านไฟร์วอลล์ไปยัง $ พอร์ตด้วย
user9517 รองรับ GoFundMonica

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

1
@lesto ที่จริงแล้วฉันคิดว่าการเปิดเผย VPN เพิ่มพื้นผิวการโจมตีอย่างหนาแน่นเมื่อเทียบกับบริการที่ จำกัด เพียงครั้งเดียว ผู้คนลืมว่า VPN จะกลายเป็นช่องทางโจมตีสำหรับมัลแวร์ใด ๆ บนเครื่องระยะไกลเพื่อเจาะระบบความปลอดภัยในขอบเขตทั้งหมดและไปที่เครือข่ายที่กล้าหาญ ฉันพบว่าพวกเขายอมรับได้ก็ต่อเมื่อพวกเขาเชื่อมต่อกับ DMZ ที่ถือว่าพวกเขาเป็นพิษเช่นเดียวกับโฮสต์อินเทอร์เน็ต
Craig Ringer

1
@CraigRinger ฉันไม่ได้บอกว่าจะลบการป้องกันที่เหลือ แต่เพื่อแค็ป
ซูล

1
@lesto แน่นอนว่าตกลง VPN อาจเป็นเลเยอร์พิเศษที่มีประโยชน์หากไม่ได้รับการปฏิบัติในฐานะ Magic Security Sauce เหมือนกับผู้ดูแลระบบจำนวนมาก
Craig Ringer

2

ส่วนขยายอย่างง่ายสู่แผนปฏิบัติการ Craigs ที่น่าประทับใจ:

บางทีผู้ใช้อาจใช้ผู้ให้บริการเครือข่ายเพียงเล็กน้อย (ตัวอย่างเช่นผู้ให้บริการเครือข่ายมือถือของเขาขณะเคลื่อนย้ายเครือข่ายเคเบิลของเขาจากที่บ้านและที่ทำงาน ip ที่ส่งออกจากที่ทำงาน)

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

สถานการณ์การสนับสนุนที่เรียบง่าย:

  1. ลูกค้าของคุณโทรหาคุณ"ฉันไม่สามารถเข้าสู่ระบบ"
  2. คุณค้นหาด้วยtcpdump -i eth0 -p tcp port 5432คำสั่งเขามาจากไหน
  3. ด้วยwhois 1.2.3.4คุณจะได้รับที่อยู่ IP ที่ใช้โดย ip นี้ 1.2.3.0/24ยกตัวอย่างเช่นมันสามารถ
  4. ด้วยiptables -A INPUT -s 1.2.3.0/24 -p tcp --dport 5432 -j ACCEPT(หรือคล้ายกัน) คุณอนุญาตการเชื่อมต่อ tcp ด้วยซับเน็ตใหม่ของเขา

มีสคริปต์ perl ที่ดีมากuifซึ่งสามารถให้ชุดกฎ iptables แบบถาวรและใช้งานง่าย (Google สำหรับ "uif iptables")


1
แนวคิดที่น่าสนใจ แต่นั่นฟังดูค่อนข้างบอบบาง
nishantjr

@nishantjr แน่นอนว่ามันไม่ใช่ทางออกแบบสแตนด์อโลนเพียงความเป็นไปได้ที่จะทำให้สิ่งต่าง ๆ ดีขึ้น
peterh กล่าวว่าคืนสถานะโมนิก้า

วิธีการปฏิบัติมากขึ้นอาจจะมีการให้บริการอินเทอร์เน็ตแต่ละรายการที่อนุญาตและ / หรือประเทศหาวิธีที่จะทำเช่นนี้เห็นเช่นstackoverflow.com/questions/16617607/...
ซิป Rodin

1

นี่คือการกำหนดค่า Fail2ban ที่ค่อนข้างง่ายสำหรับ PostgreSQL โดยอ้างอิงจาก HOWTO ที่เชื่อมโยงไว้ด้านบน แต่ได้รับการปรับแต่งให้ทำงานกับแพ็คเกจ Ubuntu ได้อย่างแท้จริงจับเงื่อนไขข้อผิดพลาดอื่นและข้ามข้อความดีบั๊กต่าง ๆ เพื่อให้เร็วขึ้น:

/etc/fail2ban/filter.d/local-postgresql.conf:

[Definition]

failregex = <HOST>\(\d+\) FATAL:  password authentication failed for .+$
            <HOST>\(\d+\) FATAL:  no pg_hba.conf entry for host .+$

ignoreregex = duration:

/etc/fail2ban/jail.d/local-postgresql.conf:

[local-postgresql]
enabled  = true
filter   = local-postgresql
action   = iptables[name=PostgreSQL, port=5432, protocol=tcp]
           sendmail-whois[name=PostgreSQL, dest=root@localhost]
logpath  = /var/log/postgresql/postgresql-9.3-main.log
maxretry = 3

1

Fail2ban เป็นเครื่องมือที่ทรงพลัง แต่ไม่น่าเชื่อว่าตัวกรองจะทำงานเหมือนที่เป็นอยู่ ทดสอบตัวกรองใด ๆ โดยใช้เครื่องมือ failregexและอย่าลืมหลีกเลี่ยงคำพูดใด ๆ (เช่น "admin" จะเป็น \ "admin \") ตัวอย่างเช่นการทดสอบบรรทัดตัวกรอง failregex ต่อไปนี้จาก /etc/log/postgresql/postgresql-9.3-main.log ของฉันไม่ทำงาน

fail2ban-regex '2016-09-20 14:30:09 PDT FATAL:  password authentication failed for user "admin"' '<HOST>\(\d+\) FATAL:  password authentication failed for .+$'

ข้างต้นให้ฉัน

Failregex: 0 ทั้งหมด

ฉันต้องอัปเดต failregex เพื่อให้ตรงกับรูปแบบบันทึก

fail2ban-regex '2016-09-20 14:30:09 PDT FATAL:  password authentication failed for user "admin"' 'FATAL:  password authentication failed for user \"<HOST>\"'

สิ่งนี้ให้ผลลัพธ์เชิงบวกแก่ฉัน

Failregex: 1 ทั้งหมด

การทดสอบ fail2ban-regex สามารถนำไปใช้กับไฟล์บันทึกทั้งหมดได้

fail2ban-regex /var/log/postgresql/postgresql-9.3-main.log /etc/fail2ban/filter.d/postgresql.local

ข้างต้นให้ผลลัพธ์ที่เป็นบวกต่อไปนี้กับ failregex ที่อัปเดต

Failregex: 169 total

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