BankID Thụy Điển là một dạng nhận dạng kỹ thuật số được hầu hết người dân Thụy Điển sử dụng để xác thực cho nhiều dịch vụ như: nhà cung cấp internet, dịch vụ ngân hàng trực tuyến, trang web cá cược và đặc biệt là các trang web của chính phủ.
Bản thân sống ở Thụy Điển và với tâm lý hacker luôn lởn vởn trong đầu, tôi quyết định rằng đây sẽ là một lĩnh vực rất thú vị để thực hiện một số nghiên cứu về bảo mật.
Trong bài đăng này, tôi sẽ trình bày một lỗ hổng mới mà tôi phát hiện thấy ở hầu hết các nhà cung cấp dịch vụ của Thụy Điển do việc triển khai giao thức xác thực của BankID không an toàn.
Tôi sẽ giới thiệu ngắn gọn về cách thức hoạt động của một giao thức như vậy, cấu hình dễ bị tổn thương trông như thế nào, cách khai thác, cách khắc phục và cuối cùng là ý nghĩa của các kiểu tấn công này đối với việc triển khai tổng thể eID.
BankID là một dịch vụ được cài đặt trên thiết bị của người dùng và có được bằng cách yêu cầu dịch vụ đó từ ngân hàng Thụy Điển, với điều kiện là bạn có persunnumer Thụy Điển , mã tài chính cá nhân. Ứng dụng được cài đặt trên thiết bị của người dùng và được kết nối với mã tài chính của họ, về cơ bản là gắn danh tính của người đó với ứng dụng đó. Đây thường là cách hoạt động của các hệ thống nhận dạng điện tử: bên thứ ba được chính phủ ủy quyền và đáng tin cậy trao một phần mềm gắn liền với một cá nhân cụ thể, sau đó các dịch vụ sẽ tích hợp với nhà cung cấp phần mềm đó để cho phép người dùng của họ xác thực trên tài khoản của họ. nền tảng, một mô hình tin cậy được chia sẻ cho phép các dịch vụ dễ dàng xác thực mọi người.
BankID cũng không khác và nó cung cấp tài liệu cho các dịch vụ như vậy, từ giờ trở đi sẽ được gọi là Bên tin cậy (RP), để họ có thể dễ dàng tích hợp luồng xác thực của mình với BankID. https://www.bankid.com/en/utvecklare/guider/teknisk-integrationsguide/rp-introduktion .
Với BankID, hai luồng chính được sử dụng để xác thực người dùng:
Xác thực trên cùng một thiết bị
Xác thực trên thiết bị khác
Chúng tôi sẽ sớm xem lại hai luồng này, tuy nhiên, cả hai luồng đều bắt đầu bằng việc RP gửi yêu cầu tới API của BankID để bắt đầu yêu cầu xác thực. Trong yêu cầu đăng bài này, RP phải chỉ định tham số endUserIp
, tham số này chứa IP của người dùng đang cố đăng nhập, điều này sẽ rất quan trọng trong báo cáo sau này.
Điểm cuối API /auth
sẽ phản hồi như thế này:
HTTP/1.1 200 OK Content-Type: application/json { "orderRef":"131daac9-16c6-4618-beb0-365768f37288", "autoStartToken":"7c40b5c9-fa74-49cf-b98c-bfe651f9a7c6", "qrStartToken":"67df3917-fa0d-44e5-b327-edcc928297f8", "qrStartSecret":"d28db9a7-4cde-429e-a983-359be676944c" }
orderRef
là mã định danh mà RP có thể sử dụng đối với điểm cuối /collect
để kiểm tra trạng thái xác thực và sau đó lấy thông tin người dùng cần từ người đóautoStartToken
là mã thông báo được RP sử dụng để tạo liên kết sâu mà khi nhấp vào sẽ mở ứng dụng BankID và nhắc người dùng tự xác thực ( Điều này sẽ thực sự quan trọng ) qrStartToken
và qrStartSecret
sẽ được đề cập bên dưới nhưng không thực sự quan trọng đối với nghiên cứu bảo mật được thực hiện.
Ngoài IP của người dùng, RP có thể chỉ định thêm tham số cho lệnh xác thực, bao gồm văn bản sẽ hiển thị trên ứng dụng BankID và các yêu cầu xác thực .
Trong số các yêu cầu xác thực, những yêu cầu mà bài đăng này sẽ tập trung vào được gọi là chính sách chứng chỉ , những yêu cầu này cho phép RP giao tiếp với BankID, luồng nào trong hai luồng đã được người dùng chọn.
Khi người dùng chọn xác thực bằng BankID trên cùng một thiết bị, RP sẽ sử dụng autoStartToken
để tạo một liên kết sâu trông giống như: bankid:///?autostarttoken=7c40b5c9-fa74-49cf-b98c-bfe651f9a7c6&redirect=https://service.com/login
. Liên kết sâu này sau đó được hệ điều hành của người dùng chọn và chuyển đến ứng dụng BankID.
Trong khi điều tra luồng này, người ta đã tìm thấy một lỗ hổng Open Redirect do không có xác thực tham số redirect
từ phía BankID, tôi sẽ hiểu lý do tại sao lỗi bổ sung này khiến cuộc tấn công chiếm quyền điều khiển phiên trở nên mạnh mẽ hơn sau này.
Khi người dùng chọn xác thực bằng BankID trên một thiết bị khác, RP sẽ sử dụng qrStartToken
và qrStartSecret
để tạo mã QR động (bằng cách tìm nạp dữ liệu của khung tiếp theo từ điểm cuối /collect
đã nói ở trên) mà người dùng có thể quét bằng Mobile BankID của mình ứng dụng.
Những điều này NÊN được RP chỉ định khi bắt đầu yêu cầu xác thực, chúng cho phép BankID từ chối nỗ lực xác thực nếu luồng không khớp để giảm thiểu lừa đảo. Ví dụ: nếu người dùng chọn “xác thực trên cùng một thiết bị”, RP sẽ thông báo điều đó tới BankID để nếu cố gắng xác thực trên Mobile BankID và/hoặc sử dụng mã QR, ứng dụng có thể từ chối điều đó.
Ngoài những điều này, sau khi quá trình xác thực hoàn tất, RP có thể tìm nạp ipAddress
được sử dụng để mở ứng dụng BankID từ điểm cuối API /collect
. Điều này NÊN được kiểm tra dựa trên địa chỉ IP của người dùng trên RP trong trường hợp anh ta đã chọn “xác thực trên cùng một thiết bị”.
Các chính sách chứng chỉ, cùng với ipAddress
NÊN được sử dụng để đảm bảo rằng luồng xác thực không thể bị giả mạo.
Tuy nhiên, trong khi các biện pháp bảo mật này được áp dụng, BankID không nêu rõ tầm quan trọng của chúng và không triển khai chúng một cách chính xác ngay cả khi triển khai ví dụ được cung cấp! https://github.com/BankID/SampleCode
Vậy điều gì sẽ xảy ra khi giao thức này không được triển khai an toàn?
Khi tôi nhìn thấy liên kết sâu bankid:///
lần đầu tiên, tôi đang xem các mẫu đơn đăng ký vào trường đại học của mình. Mẫu này có thể được truy cập bằng cách đăng nhập bằng BankID. Lúc đầu, tôi nghĩ: điều gì sẽ xảy ra nếu tôi gửi liên kết sâu này cho ai đó? Vì vậy, tôi đã gửi nó cho một người bạn của tôi, người đã nhấp vào nó và thật ngạc nhiên sau khi anh ấy mở BankID, tôi đã có trước mặt tất cả đơn đăng ký vào trường đại học của anh ấy!
Đó là khi tôi bắt đầu xem xét API của BankID, triển khai RP của riêng mình và tìm hiểu về tất cả những điều tôi vừa nêu.
Sau vài tuần nghiên cứu, tôi đã phát triển một tập lệnh tự động lấy liên kết sâu bankid:///
cho hơn 30 RP, tập lệnh sẽ khởi động máy chủ web và tạo đường dẫn cho từng dịch vụ khi người dùng truy cập liên kết cho một dịch vụ cụ thể, tập lệnh sẽ tìm nạp một liên kết mới và chuyển hướng người dùng đến liên kết đó. Điều này sẽ khiến thiết bị của người dùng mở ứng dụng BankID và sau khi xác thực, tôi sẽ được xác thực thay vì họ.
Tôi đã có thể làm điều này bởi vì:
RP đã không gửi chính sách chứng chỉ tới BankID, giúp tôi có thể tìm nạp liên kết sâu và chuyển tiếp nó tới ứng dụng Mobile BankID
RP không so sánh địa chỉ IP yêu cầu liên kết với địa chỉ IP đã hoàn tất xác thực
RP đã cung cấp liên kết ngay cả khi tùy chọn “xác thực trên thiết bị khác” được chọn
Điều này dẫn đến lỗ hổng Session Fixation.
Hãy tưởng tượng một dịch vụ dễ bị tấn công có tên là AmazingSevice AB, họ đã triển khai luồng BankID theo mã mẫu được cung cấp và đang lưu trữ hoạt động triển khai đó tại https://amazingservice.se/login/bankid
.
Kẻ đe dọa quan tâm đến dữ liệu người dùng được lưu trữ trên AmazingSevice AB và đã để mắt đến nạn nhân của hắn. Anh ta chỉ cần tự động hóa việc lấy liên kết bankid:///
, lưu trữ nó trên máy chủ của mình và sau đó gửi liên kết đến máy chủ độc hại của mình cho nạn nhân. Sau khi chọn cách gửi lượt thích lừa đảo (SMS, email, v.v.), anh ta sẽ nhúng liên kết vào tin nhắn giả danh AmazingSevice AB và yêu cầu nạn nhân đăng nhập.
Việc chiếm đoạt tài khoản như vậy đòi hỏi rất ít kỹ thuật xã hội vì khi nạn nhân nhấp vào liên kết, anh ta ngay lập tức được nhắc mở BankID, rời khỏi “lãnh thổ không xác định” trên trang web của kẻ tấn công để đến một giao diện quen thuộc hơn nhiều, BankID. Ngoài ra, yêu cầu xác thực mà nạn nhân thấy trong ứng dụng BankID được yêu cầu bởi AmazingSevice AB, khiến không thể phát hiện hành vi gian lận.
Sau khi nạn nhân xác thực, phiên của kẻ tấn công được xác thực vào tài khoản của nạn nhân, nạn nhân có thể bị lừa thêm bằng cách khai thác lỗ hổng Open Redirect có trong BankID, cho phép kẻ tấn công chỉ định tham số redirect
là https://amazingservice.se/login/bankid
. Điều này sẽ khiến nạn nhân được chuyển hướng đến trang web dịch vụ hợp pháp, khiến anh ta chỉ nghĩ rằng việc xác thực không thành công.
Tôi không thể sử dụng một trong những công ty mà tôi đã báo cáo, vì những lý do rõ ràng, vì vậy thay vào đó, bản demo cho thấy dịch vụ demo của BankID dễ bị tấn công bởi điều này!
Ở góc bên phải là góc nhìn từ nạn nhân nhận link, ở đây được mô phỏng bằng cách truy cập vào trang web của kẻ tấn công. Sau khi nạn nhân truy cập vào liên kết, máy chủ của kẻ tấn công sẽ mở trình duyệt không có giao diện người dùng và trích xuất liên bankid:///
sau đó được chuyển tiếp đến điện thoại của nạn nhân. Trong ứng dụng BankID, bạn có thể thấy “Test av BankID” là nguồn gốc hợp pháp cho trang demo của BankID. Ngoài ra, ở đầu video, VPN được bật để thấy rằng không có hoạt động kiểm tra địa chỉ IP nào được thực hiện trong quá trình xác thực. Cuối cùng, có thể thấy trên máy tính xách tay của kẻ tấn công, anh ta đăng nhập với tư cách là nạn nhân (Johan Johansson).
Lỗi Sửa phiên dẫn đến chiếm đoạt tài khoản chỉ bằng 1 cú nhấp chuột trên bất kỳ ứng dụng nào sử dụng BankID Thụy Điển làm nhà cung cấp xác thực và đã triển khai không chính xác (hoặc hoàn toàn không) các chính sách chứng chỉ và kiểm tra ipAddress
. Điều này khá nghiêm trọng vì đôi khi các dịch vụ đang sử dụng BankID để xác thực người dùng của họ có quyền truy cập vào dữ liệu và hành động khá nhạy cảm. Hơn 30 ứng dụng được phát hiện dễ bị tấn công bởi cuộc tấn công này, càng nhiều ứng dụng càng tốt đã được liên hệ, dẫn đến 11 báo cáo tiền thưởng lỗi được chấp nhận trên các nền tảng chính.
Một trong những dịch vụ mà tôi đã báo cáo về lỗ hổng này đã có thể giúp tôi liên hệ với CSIRT quốc gia của Thụy Điển do mức độ nghiêm trọng và phổ biến của vấn đề. Các cuộc thảo luận vừa mới bắt đầu nên nếu bạn muốn cập nhật hãy theo dõi tôi trên Twitter (X) @m4st3rspl1nt3r
Nếu bạn đang tìm ví dụ về cách triển khai API BankID RP an toàn, tôi đã tạo một ví dụ mà bạn có thể sử dụng làm thư viện Golang hoặc tùy chỉnh và triển khai dưới dạng vi dịch vụ. Bạn có thể tìm thấy điều đó ở đây .
Hầu hết các dịch vụ bị ảnh hưởng, đặc biệt là những dịch vụ có BBP và VDP, đều phản hồi báo cáo của tôi khá nhanh chóng và dễ tiếp thu. Tuy nhiên, phản hồi của BankID hơi khác một chút. Trong một email mà tôi nhận được sau khi liên hệ với họ nhiều lần qua nhiều kênh khác nhau, họ giải thích rằng họ đã biết về vấn đề này nhưng họ cảm thấy không thể làm gì nhiều để giải quyết vấn đề đó nhằm duy trì “dễ dàng tích hợp” cho RP. Việc giảm thiểu theo kế hoạch, rất tiếc là vẫn yêu cầu thực hiện các thay đổi về phía RP, đã được thông báo cho tôi (nhưng vì lý do nào đó không tìm thấy ở bất kỳ đâu trong tài liệu của họ) như:
Một yêu cầu bổ sung mà RP có thể đặt ra là Rủi ro. Điều này sẽ đặt ra mức rủi ro có thể chấp nhận được cho giao dịch. Nếu rủi ro của giao dịch cao hơn giới hạn yêu cầu thì giao dịch sẽ bị chặn “THẤP” - chỉ chấp nhận các lệnh có rủi ro thấp “TRUNG BÌNH” - chấp nhận các lệnh có rủi ro thấp và trung bình Nếu điều này được đặt. Bên cạnh đó, chúng tôi sẽ thực hiện việc kiểm tra IP nếu nó được RP cung cấp. Các thông số rủi ro khác sẽ được giám sát rủi ro nếu được cung cấp là referenceDomain, userAgent và deviceIdentifier.
Ngoài ra, kế hoạch khắc phục lỗ hổng Open Redirect cũng đã được đưa ra.
Ý kiến cá nhân của tôi về vấn đề này là nếu bạn phát triển và vận hành một nhà cung cấp xác thực quan trọng và được chấp nhận cao như vậy, thường được sử dụng để bảo vệ thông tin người dùng rất nhạy cảm, thì bạn nên ghi lại cơ chế bảo mật của mình một cách hợp lý để RP có thể tích hợp nó một cách an toàn. Các tính năng bảo mật tùy chọn hoàn toàn vô dụng, nếu nhà phát triển có thể tiết kiệm thời gian không triển khai một số tính năng/thông số nhất định thì điều đó sẽ xảy ra và chúng tôi không thể đổ lỗi cho phía RP. BankID nên cố gắng hết sức để chuyển nhiều tính năng chống gian lận và bảo mật sang bên mình nhằm duy trì “dễ dàng tích hợp” nhưng cũng đảm bảo ghi lại chính xác mọi tính năng bảo mật bổ sung mà RP bắt buộc phải triển khai; lưu ý về yêu cầu không phải là tùy chọn.
Phần này của blog hoàn toàn là ý kiến của tôi.
Đối với tôi, lỗ hổng này là một ví dụ cho thấy sự nguy hiểm của việc để một công ty tư nhân có toàn quyền kiểm soát một hệ thống quan trọng đối với người dân của một quốc gia. Lý do tôi tin rằng điều này nghiêm trọng hơn một lỗ hổng khác trong một công ty phần mềm là vì BankID là thứ được hơn 8,5 triệu cư dân Thụy Điển sử dụng. Nó được sử dụng để đăng nhập vào ngân hàng, nhà cung cấp bảo hiểm, nhà cung cấp điện và các nền tảng nhạy cảm khác của bạn. có những hậu quả trong thế giới thực.
Nếu ai đó tìm thấy Tài khoản TakeOver trên Facebook, bạn có thể mất một số hình ảnh, nếu ai đó tìm thấy lỗ hổng trong nhà cung cấp ID điện tử ở quốc gia bạn (thường là riêng tư) thì hậu quả đối với cuộc sống của ai đó có thể là không thể tưởng tượng được.
Ngày càng có nhiều quốc gia châu Âu áp dụng eID và EU đang có kế hoạch triển khai eID EU của riêng họ trong những năm tới (bạn có thể đọc thêm về điều này tại đây ).
Tôi hy vọng rằng các cơ quan quản lý sẽ thúc đẩy các nhà cung cấp định danh điện tử phải được các tổ chức công phát triển và kiểm soát hoàn toàn, có thể yêu cầu các hệ thống như vậy phải là nguồn mở và được kiểm tra thường xuyên để phát hiện các lỗi bảo mật.
Làm thế nào chúng ta có thể chấp nhận những phần mềm quan trọng như vậy trong xã hội một cách an toàn nếu chúng được phát triển bởi một công ty tư nhân?
Mặc dù chủ đề chính của bài đăng trên blog này là cuộc tấn công Cố định phiên vào BankID nhưng tôi nhận thấy rằng nhiều nhà cung cấp xác thực/nhận dạng khác đều được thiết kế với cùng một lỗ hổng. Một lớp lỗ hổng mới có thể được tìm thấy ở các nhà cung cấp yêu cầu sử dụng thiết bị khác (thường là điện thoại di động) để hoàn tất quy trình xác thực.
Nghiên cứu đang được tiến hành và tôi hy vọng sẽ sớm công bố thêm những phát hiện của mình cũng như một công cụ mà tôi đang nghiên cứu có thể được sử dụng để tự động hóa và khai thác những lỗ hổng như vậy. Hãy theo dõi chủ đề tiếp theo của tôi Cố định phiên theo thiết kế - Cơn ác mộng xác thực trên nhiều thiết bị
Cho đến lúc đó, hãy hack hành tinh này!