Hướng dẫn thực tế kho chứng chỉ Windows ── đưa vào kho người dùng hay kho máy tính?

· · Chứng chỉ, Windows, Bảo mật, PKI, TLS, PowerShell, Ứng dụng nghiệp vụ, Hệ thống thông tin

“Cập nhật máy xác nhận tư cách trực tuyến, đưa lại chứng chỉ máy khách vào PC mới thì không kết nối được.” “Máy phát triển nối được API ngân hàng, biến thành dịch vụ Windows thì báo ‘không tìm thấy chứng chỉ’.” “Chứng chỉ thấy trên certmgr.msc và chứng chỉ thấy trên certlm.msc, không biết cái nào là thật.” ── Khi nhận phát triển phần mềm theo yêu cầu cho liên kết Web API kèm chứng chỉ máy khách, kiểu hỏi này đến đều đặn.

Xác nhận tư cách trực tuyến của cơ sở y tế, nộp điện tử, API dòng ngân hàng, EDI với đối tác. Chứng chỉ máy khách từng chỉ người hạ tầng doanh nghiệp lớn chạm, nay nhân viên IT doanh nghiệp vừa và nhỏ cùng nhà phát triển ứng dụng nghiệp vụ cũng xử lý. Và tai nạn quanh chứng chỉ thực ra gom vào vài mẫu. Nhầm chỗ đưa vào, quên quyền khóa riêng, quên hạn ── ba điều đó.

Bài viết này hướng tới nhà phát triển ứng dụng nghiệp vụ dùng chứng chỉ máy khách, và nhân viên IT được giao việc thay chứng chỉ. Lấy quyết định “đưa vào kho người dùng hay kho máy tính” làm trục, nó gom một mạch từ cấu trúc kho chứng chỉ Windows, cấp quyền khóa riêng, kiểm kê hạn bằng PowerShell, đến mã dùng từ .NET. Nội dung dựa trên nguồn gốc Microsoft Learn tính đến tháng 8 năm 2026.

1. Kết luận trước

  • Kho chứng chỉ Windows có hai hệ: “người dùng (CurrentUser)” và “máy tính (LocalMachine)”. Kho người dùng khác nhau theo tài khoản (dưới registry HKEY_CURRENT_USER); kho máy tính dùng chung cả PC (dưới HKEY_LOCAL_MACHINE).12
  • Cũng có hai công cụ quản. certmgr.msc mở kho người dùng hiện tại; certlm.msc mở kho máy tính cục bộ. Từ PowerShell là Cert:\CurrentUserCert:\LocalMachine.34
  • Đưa vào bên nào quyết theo “chương trình dùng chứng chỉ đó chạy với tư cách ai”. Ứng dụng người dùng tương tác thì kho người dùng; chạy không người của dịch vụ Windows, IIS, Task Scheduler thì nguyên tắc là kho máy tính (bảng quyết định Chương 3).
  • Nguyên nhân “lúc phát triển thì chạy, biến thành dịch vụ thì không tìm thấy” gần như chỉ một. Chứng chỉ nhà phát triển đưa vào kho người dùng của mình thì CurrentUser của dịch vụ chạy bằng tài khoản khác không thấy (Chương 3).
  • Chứng chỉ và khóa riêng là hai thứ khác nhau. Chỉ đưa vào kho máy tính thì tài khoản dịch vụ thường không đọc được khóa riêng. Cấp quyền đọc cho tài khoản chạy bằng “Manage Private Keys” trên certlm.msc.5
  • Lúc nhập pfx, khóa riêng mặc định không xuất được. Import-PfxCertificate không nhập lại được khóa riêng để xuất lại trừ khi chỉ định -Exportable. Đó không phải tai nạn mà là mặc định đáng muốn.6
  • Hết hạn được ngăn bằng tự động hóa kiểm kê. Rút máy móc chứng chỉ hết hạn trong số ngày chỉ định, kiểu Get-ChildItem Cert:\LocalMachine\My -ExpiringInDays 60.4
  • Gắn cứng thumbprint vào mã hoặc cấu hình thì chết mỗi lần gia hạn chứng chỉ. Chứng chỉ mới luôn đổi thumbprint. Đưa cấu hình ra ngoài + giai đoạn chạy song song cũ-mới là cơ bản của thiết kế (Chương 5, 7).

Bản đồ tri thức của bài viết này

Kho chứng chỉ Windows chia hai hệ người dùng (CurrentUser) và máy tính (LocalMachine); chứng chỉ máy khách đưa vào bên nào quyết theo chương trình đó chạy với tư cách ai. Dịch vụ Windows chạy không người đi một bộ kho máy tính và cấp quyền khóa riêng; hết hạn chứng chỉ và thumbprint gắn cứng là nguyên nhân quen của sự cố kết nối do chứng chỉ.

Bản đồ tri thức hướng dẫn thực tế kho chứng chỉ WindowsSơ đồ cho thấy quan hệ kho chứng chỉ (người dùng/máy tính), chứng chỉ máy khách, khóa riêng, chuỗi chứng chỉ, CA gốc và CA trung gian, hết hạn cùng thumbprint với sự cố kết nối, quy trình thay, sổ cái, và rủi ro chứng chỉ tự kýsử dụngyêu cầuyêu cầuyêu cầuyêu cầucó thể gâycó thể gâyxác minh bằngcấu hình bằngcấu hình bằngxác minh bằngxác minh bằngxác minh bằngxác minh bằnglưu trongxác minh bằnglưu trongsử dụnglưu trongcấu hình bằngngăn chặnngăn chặncó thể gâykhông khuyến nghịkhông khuyến nghịkhuyến nghị chokế thừa nội dunglưu trongcó thể gâysử dụngyêu cầusử dụngcó thể gâykhông khuyến nghịyêu cầunên làm trướcsử dụnggiảm thiểuyêu cầukhuyến nghị chokhuyến nghị choKho chứng chỉChứng chỉ máy kháchDịch vụ WindowsKho chứng chỉ máy tínhKhóa riêngQuyền truy cập khóa riêngChuỗi chứng chỉChứng chỉ CA trung gianChứng chỉ CA gốcHết hạn chứng chỉSự cố kết nối do chứng chỉGắn cứng thumbprintGroup PolicyMicrosoft IntuneKho chứng chỉ người dùngcertmgr.msccertlm.mscỔ Cert:Tệp PFXcertutilChứng chỉ ký mãKho Trusted PublishersỨng dụng desktop người dùng tương tácThay chứng chỉSổ cái chứng chỉChứng chỉ tự ký ad-hocRủi ro lạm dụng điểm tin cậyChọn (tìm) chứng chỉKho Personal (My)Nhầm khoIIS application poolChạy không người qua Task SchedulerNhập ở dạng xuất đượcRủi ro mang khóa riêng ra ngoàiCấp Full control cho EveryoneĐăng ký chứng chỉ trước với đối tácChuyển sang chứng chỉ mớiLớp X509StoreTìm chứng chỉ với validOnlyThuộc tính Key UsageĐưa thumbprint ra cấu hìnhGhi nhật ký chứng chỉ đã chọn

Trong sơ đồ, đường liền nét biểu thị quan hệ luôn đúng và đường nét đứt biểu thị quan hệ có điều kiện (điều kiện nằm trong phần giải thích từng quan hệ trên trang chi tiết). Danh sách đầy đủ các quan hệ (tổng 41, kèm bằng chứng và mức chắc chắn) cùng định nghĩa các khái niệm chính được tập hợp tại trang chi tiết bản đồ tri thức (bằng tiếng Nhật). Dữ liệu: JSON-LD / Turtle

2. Toàn cảnh kho chứng chỉ ── hai chỗ và kho logic

2.1. Hai hệ người dùng và máy tính

Kho chứng chỉ Windows chia lớn thành hai “chỗ”.1

  • Kho chứng chỉ máy tính (máy tính cục bộ, LocalMachine): một cái trên PC đó, dùng chung cho mọi người dùng và dịch vụ trên PC. Thực thể nằm dưới registry HKEY_LOCAL_MACHINE\Software\Microsoft\SystemCertificates.2
  • Kho chứng chỉ người dùng (người dùng hiện tại, CurrentUser): khác nhau theo tài khoản người dùng. Thực thể nằm dưới HKEY_CURRENT_USER\Software\Microsoft\SystemCertificates, tức một phần hồ sơ người dùng.2

Ngoài ra còn kho theo tài khoản dịch vụ3, thực thể là khóa registry theo tên dịch vụ.2 Việc thực tế cần nắm trước là hai cái đầu.

Có một đặc tả quan trọng. Mỗi kho logic của kho người dùng, trừ “Personal”, kế thừa nội dung kho cùng tên của kho máy tính rồi hiện.1 Ví dụ đưa chứng chỉ CA nội bộ vào “Trusted Root Certification Authorities” của kho máy tính thì chứng chỉ đó cũng hiện trên “Trusted Root Certification Authorities” của mọi người dùng. Nói ngược, chỉ kho “Personal” không được kế thừa, nên chứng chỉ máy khách (= thứ đưa vào kho Personal) phải tự quyết “cần ai thấy”. Sự bất đối xứng đó là nhân vật chính của cả bài này.

Kho máy tính và kho người dùngKho máy tính có một cái trên PC dùng chung mọi người dùng và dịch vụ; kho người dùng khác nhau theo tài khoản và trừ Personal thì kế thừa nội dung phía máy tính rồi hiệnNgười dùng (CurrentUser)khác nhau theo tài khoảnMáy tính (LocalMachine)một cái trên PC, dùng chung mọi người dùng và dịch vụkế thừa nội dung rồi thấykế thừakế thừaPersonal (My)※không kế thừa = chỗ tự quyết nơi đưa vàoTrusted Root Certification Authorities (Root)Intermediate Certification Authorities (CA)Trusted Publishers (TrustedPublisher)Personal (My)Trusted Root Certification Authorities (Root)Intermediate Certification Authorities (CA)Trusted Publishers (TrustedPublisher)

Hình 1: Kho người dùng trừ Personal thì kế thừa nội dung kho máy tính rồi hiện; chỗ đưa chứng chỉ máy khách phải tự quyết.

2.2. Các kho logic chính

Trong mỗi chỗ chia thành kho logic theo vai trò. Thư mục thấy trên certmgr.msc / certlm.msc chính là chúng; khi xem từ PowerShell hay lệnh thì dùng tên nội bộ tiếng Anh.24

Tên hiển thị Tên nội bộ Chỗ đưa gì vào
Personal My Chứng chỉ mà mình (PC này, người dùng này) dùng. Chứng chỉ máy khách và chứng chỉ máy chủ ở đây. Cái gắn với khóa riêng cũng ở đây
Trusted Root Certification Authorities Root Chứng chỉ CA gốc làm điểm tin cậy. Cấp dưới của CA đưa vào đây được “tin”
Intermediate Certification Authorities CA Chứng chỉ CA trung gian nối gốc và đầu cuối. Nguyên liệu dựng chuỗi
Trusted Publishers TrustedPublisher Chứng chỉ tin với tư cách nhà phát hành phần mềm đã ký (Chương 8)

2.3. Ba cửa sổ nhìn ── certmgr.msc / certlm.msc / ổ Cert:

Có ba cách nhìn cùng một kho.34

  • certmgr.msc: bảng điều khiển quản mở kho người dùng hiện tại.
  • certlm.msc: bảng điều khiển quản mở kho máy tính cục bộ.
  • Cert: của PowerShell: thao tác kho như hệ thống tệp theo tầng Cert:\CurrentUser\...Cert:\LocalMachine\.... Chứng chỉ được nhận diện bằng thumbprint.

Khi thêm snap-in chứng chỉ thủ công vào mmc.exe, bạn chọn đối tượng từ ba loại “User account”, “Computer account”, “Service account”. Người dùng không phải quản trị viên chỉ quản được kho tài khoản người dùng của mình.3

Bước đầu điều tra sự cố là khớp “ứng dụng đang nhìn kho nào” với “mình đang nhìn kho nào”. Ngắm certmgr.msc mà điều tra sự cố dịch vụ thì chỗ nhìn khác, mãi không ra đáp án.

3. Đưa vào bên nào ── bảng quyết định theo hình thức chạy của chương trình

Tiêu chí quyết định chỉ một. Chương trình dùng chứng chỉ đó chạy bằng tài khoản của ai.

Hình thức chạy Tài khoản chạy Kho đưa vào Ghi chú
Ứng dụng desktop do người dùng tương tác khởi động Chính người dùng đăng nhập Người dùng (Cert:\CurrentUser\My) Cần triển khai theo tài khoản người dùng. PC dùng chung nhiều người thì cân kho máy tính
Dịch vụ Windows LocalSystem / NETWORK SERVICE / tài khoản dịch vụ riêng Máy tính (Cert:\LocalMachine\My) Ngoài LocalSystem (NETWORK SERVICE, tài khoản riêng, v.v.) bắt buộc cấp quyền đọc khóa riêng (Chương 4). LocalSystem đọc được bằng quyền SYSTEM mặc định
Ứng dụng web trên IIS ID của application pool Máy tính Như trên
Chạy không người của Task Scheduler (chạy bất kể người dùng có đăng nhập) Tài khoản chỉ định trên tác vụ Khuyến nghị máy tính Chạy được bằng kho người dùng của tài khoản chạy, nhưng chỉ tăng việc kiểm hồ sơ và cách kho hiện, lợi ích ít
Nộp điện tử / xác thực web trên trình duyệt Chính người dùng đăng nhập Người dùng Cũng tự nhiên theo nghĩa không để người khác ngoài người được phát dùng

Phân vân thì thứ chạy không người vào kho máy tính, thứ người thao tác vào kho người dùng.

3.1. Giải phẫu tai nạn quen ── “lúc phát triển thì chạy, biến thành dịch vụ thì không tìm thấy”

Tai nạn này tái hiện đúng bằng các bước sau.

  1. Nhà phát triển nhấp đúp pfx trên PC mình để nhập. Mặc định của wizard là “Current User”, nên chứng chỉ vào kho người dùng của tài khoản nhà phát triển.
  2. Ứng dụng lúc phát triển chạy từ Visual Studio, tức bằng tài khoản nhà phát triển, nên mở StoreLocation.CurrentUser thì tìm thấy chứng chỉ. Chạy.
  3. Đăng ký như dịch vụ Windows trên máy chủ sản xuất. Dịch vụ chạy bằng NETWORK SERVICE hoặc tài khoản riêng.
  4. CurrentUser mà mã dịch vụ mở là kho người dùng của tài khoản chạy dịch vụ. Chỗ đó trống. “Không tìm thấy chứng chỉ”.
Lúc phát triển thì chạy, biến thành dịch vụ thì không tìm thấyChứng chỉ đưa vào kho người dùng của nhà phát triển không thấy từ CurrentUser của dịch vụ chạy bằng tài khoản khácMáy chủ sản xuấtMáy phát triểnđặt cùng chương trìnhCurrentUser mà mã mở làkho người dùng của tài khoản dịch vụĐăng ký như dịch vụ Windowstài khoản chạy là NETWORK SERVICE, v.v.Chỗ đó trống→ 「không tìm thấy chứng chỉ」Vào kho người dùng củatài khoản nhà phát triểnNhấp đúp pfx để nhậpmặc định wizard là 「Current User」Chạy từ Visual Studio= chạy bằng tài khoản nhà phát triểnMở CurrentUser thì tìm thấy→ chạy

Hình 2: Kho người dùng của nhà phát triển và kho người dùng của tài khoản dịch vụ khác nhau; lúc phát triển chạy không bảo đảm tìm thấy trên sản xuất.

Điểm then chốt: kho người dùng “tồn tại đúng bằng số tài khoản”. Quản trị viên mở certmgr.msc rồi “đã vào rồi mà?” cũng chỉ là kho của chính quản trị viên, không phải kho của tài khoản dịch vụ. Đối phó không phải sao chép tùy hứng mà là đưa lại vào kho máy tính, khớp mã sang StoreLocation.LocalMachine. Và cấp quyền chương sau là một bộ.

4. Khóa riêng và quyền truy cập ── tai nạn quen thứ hai

4.1. Chứng chỉ và khóa riêng là hai thứ khác nhau

Cái thấy trên danh sách kho chứng chỉ là chứng chỉ (thông tin công khai), không phải bản thân khóa riêng. Xác thực máy khách thật sự cần là xử lý ký bằng khóa riêng, nên “thấy trên danh sách” và “dùng được” là bài toán khác. Nhầm chỗ này thì thành sự cố khó nhìn: “có chứng chỉ nhưng bắt tay TLS thất bại”, “lỗi nội bộ kiểu Access Denied”.

4.2. Thực tế nhập pfx ── xuất được hay không là quyết định

Cặp chứng chỉ và khóa riêng được trao bằng tệp pfx (PKCS #12), nhập vào kho bằng Import-PfxCertificate.6

$pwd = Get-Credential -UserName '(nhập mật khẩu bên dưới)' -Message 'Mật khẩu PFX'
Import-PfxCertificate -FilePath C:\certs\client.pfx `
    -CertStoreLocation Cert:\LocalMachine\My -Password $pwd.Password

Điểm quan trọng: trừ khi gắn -Exportable, khóa riêng đã nhập không xuất lại được — đó là hành vi mặc định.6 Đưa hết vào dạng xuất được vì “để sau này chuyển”, là thêm một đường mang khóa riêng ra. Hãy vận hành lưu pfx gốc an toàn, và khóa riêng trên kho cơ bản không xuất được ── đó là khuyến nghị của chúng tôi. Việc lưu pfx gốc và mật khẩu của nó cũng dễ bị để dạng thuần. Cách nghĩ nằm trong “Lưu bí mật của ứng dụng Windows ── tránh thiết lập thuần bằng DPAPI” và “Xử lý an toàn thông tin đăng nhập bằng PowerShell”.

4.3. Cấp quyền khóa riêng cho tài khoản dịch vụ

Khóa riêng của chứng chỉ đưa vào kho máy tính thường mặc định không đọc được từ ngoài quản trị viên và SYSTEM. Vì thế dịch vụ chạy bằng LocalSystem đọc được khóa riêng với mặc định, nhưng khi chạy bằng tài khoản khác — NETWORK SERVICE, tài khoản dịch vụ riêng, ID application pool IIS — thì cấp tường minh quyền đọc cho tài khoản chạy. Quy trình làm từ UI của snap-in chứng chỉ.5

  1. Mở certlm.msc (hoặc snap-in chứng chỉ đối tượng Computer account).
  2. “Personal” → “Certificates”, chuột phải chứng chỉ đích, từ “All Tasks” mở “Manage Private Keys”.
  3. Trên tab “Security”, thêm tài khoản chạy (NETWORK SERVICE, tài khoản dịch vụ riêng, ID application pool IIS, v.v.) rồi cho phép “Read”.5

Full control không cần. Chỉ dùng để ký thì đọc là đủ. Ngược lại, vì không chạy mà cấp Full control cho Everyone là hạ khóa riêng xuống mức mật khẩu thuần, tuyệt đối tránh. Đặt vào kho máy tính và cấp quyền khóa riêng luôn là một bộ ── chỉ cần viết vào runbook, tai nạn hệ này biến mất.

5. Ngăn tai nạn hết hạn ── kiểm kê, thay, sổ cái

5.1. Kiểm kê bằng PowerShell

Hạn chứng chỉ nằm ở thuộc tính NotAfter. Kiểm kê máy móc bằng Get-ChildItem trên ổ Cert:.4

# Liệt kê "Personal" của kho máy tính theo hạn
Get-ChildItem Cert:\LocalMachine\My |
    Sort-Object NotAfter |
    Format-Table Thumbprint, Subject, NotAfter

# Chỉ rút cái hết hạn trong 60 ngày (0 thì ra đã hết hạn)
Get-ChildItem -Path Cert:\LocalMachine\My -ExpiringInDays 60

-ExpiringInDays là tham số trả “chứng chỉ hết hạn trong số ngày chỉ định”; 0 thì ra chứng chỉ đã hết hạn.4 Biến thành scheduled task hàng tháng chạy khắp máy chủ, gom kết quả vào email hay sổ cái ── chỉ thế gần như chặn được tai nạn kiểu “hết hạn nên sáng thứ Hai xác nhận tư cách không thông”.

5.2. Quy trình thay ── giai đoạn chạy song song cũ-mới và bẫy thumbprint

Gia hạn chứng chỉ không phải “xóa rồi đưa vào” mà là “thêm rồi chuyển, xác nhận rồi mới xóa”.

  1. Nhập chứng chỉ mới (pfx) vào cùng kho. Thumbprint khác nên cũ và mới cùng tồn tại trên cùng kho.
  2. Cấp quyền khóa riêng cho chứng chỉ mới (Chương 4). Đây là chỗ dễ quên lúc gia hạn. Quyền gắn theo từng khóa riêng của chứng chỉ, nên thay chứng chỉ thì cấp lại.
  3. Báo với hệ thống đối tác (API cần đăng ký chứng chỉ trước) trong khi vẫn vận hành bằng chứng chỉ cũ, bảo đảm giai đoạn chạy song song nhận cả cũ lẫn mới. Chuyển trước thì phía đối tác từ chối chứng chỉ mới và giao tiếp sản xuất dừng.
  4. Chuyển cấu hình ứng dụng sang chứng chỉ mới, xác nhận hoạt động.
  5. Sau đủ thời gian, xóa chứng chỉ cũ.
Gia hạn chứng chỉ thì thêm rồi chuyểnNhập pfx mới vào cùng kho, cấp quyền, đăng ký trước với đối tác rồi mới đổi thumbprint, sau giai đoạn chạy song song mới xóa chứng chỉ cũ1. Nhập pfx mới vào cùng kho(cũ và mới cùng tồn tại)2. Cấp quyền khóa riêngcho chứng chỉ mới3. Đăng ký trước với đối tác(vẫn vận hành bằng chứng chỉ cũ)4. Đổi thumbprint cấu hình rồichuyển / xác nhận hoạt động5. Sau giai đoạn chạy song songxóa chứng chỉ cũ

Hình 3: Thứ tự thay chứng chỉ là thêm → cấp quyền → đăng ký trước → đổi cấu hình → xóa cũ; đừng quên cập nhật thumbprint.

Bẫy lớn nhất lúc này là thumbprint viết trong tệp cấu hình hoặc mã. Thumbprint độc nhất theo chứng chỉ nên gia hạn thì luôn đổi. Chỉ một chỗ còn trỏ thumbprint cũ thì thành “đã gia hạn chứng chỉ mà không kết nối được”. Cách chắc là quản bằng sổ cái thumbprint đang viết ở đâu (cấu hình ứng dụng, liên kết IIS, kịch bản, báo với đối tác).

5.3. Khuyến nghị sổ cái chứng chỉ

Sổ cái, trước hết một tờ Excel là đủ. Tối thiểu tạo cột mục đích / nhà phát hành / subject / thumbprint / chỗ đang vào (tên máy chủ + kho) / tài khoản giữ quyền khóa riêng / hạn / liên kết quy trình gia hạn / người phụ trách, rồi đối chiếu với kết quả kiểm kê 5.1. Thực tế tai nạn chứng chỉ không phải bài toán kỹ thuật mà là bài toán “không ai giữ danh sách”, nên sổ cái có hiệu nhất.

6. Đọc giải kiểm tra và thất bại ── chuỗi và phân phối gốc

6.1. Cơ bản kiểm tra chuỗi và certutil

Lỗi kiểu “chứng chỉ này không được tin” là trạng thái chuỗi (đường chứng minh) từ chứng chỉ đầu cuối tới CA gốc đứt ở đâu đó. Để khoanh vùng, certutil tiện.7

Ba nguyên nhân quen khi kiểm chuỗi bị đứtKhông lấy được CA trung gian, gốc chưa phân phối, hoặc đầu cuối hết hạn đều dẫn tới lỗi tin cậykhông lấy được(không trình, AIA, cũng không kho)chưa phân phốihết hạnChứng chỉ đầu cuối(chứng chỉ máy khách, chứng chỉ máy chủ)Chứng chỉ CA trung gianchỗ đặt: kho Intermediate Certification Authorities (CA)Chứng chỉ CA gốcchỗ đặt: Trusted Root Certification Authorities (Root)Không dựng được chuỗi(nguyên nhân quen 1)Lỗi 「không được tin」(nguyên nhân quen 2)Lỗi thời hạn hiệu lực(nguyên nhân quen 3)

Hình 4: Chuỗi đứt khi thiếu CA trung gian hoặc gốc, hoặc vì thời hạn hiệu lực; hãy xác định tầng bằng certutil.

:: Dựng và kiểm tra chuỗi của tệp chứng chỉ (kèm lấy URL kiểm thu hồi)
certutil -urlfetch -verify client.cer

:: Nếu ứng dụng đích dùng kho người dùng, gắn -user để kiểm cùng ngữ cảnh
certutil -user -urlfetch -verify client.cer

:: Dump nội dung kho (gắn -user thì kho người dùng)
certutil -store My
certutil -user -store My

certutil -verify kiểm chứng chỉ, CRL, chuỗi; không chỉ định CACertFile thì dựng chuỗi đầy đủ rồi kiểm.7 Đầu ra dài, nhưng đọc được tầng nào tin đứt, thông tin thu hồi có lấy được không. Nguyên nhân điển hình có ba: (1) không lấy được chứng chỉ CA trung gian (đối tác TLS không gửi, cũng không lấy từ thông tin AIA của chứng chỉ, cũng không vào kho “Intermediate Certification Authorities”), (2) gốc của CA nội bộ chưa phân phối vào “Trusted Root Certification Authorities”, (3) bản thân chứng chỉ hết hạn. CA trung gian cũng được giải bằng phía đối tác trình hoặc lấy tự động qua AIA, nên đặt vào kho hãy coi là “một trong các cách làm chắc”.

6.2. Phân phối gốc CA nội bộ và tự ký bằng GPO/Intune

Khi dùng CA nội bộ hoặc chứng chỉ tự ký để kiểm, cần phát chứng chỉ gốc đó tới từng PC. Đừng đưa tay từng máy; hãy lên cơ chế phân phối.

  • Môi trường Active Directory (GPO): nhập chứng chỉ vào “Trusted Root Certification Authorities” dưới Computer Configuration\Policies\Windows Settings\Security Settings\Public Key Policies của Group Policy thì được phân phối tới PC đối tượng.8
  • Môi trường quản Intune: phân phối chứng chỉ CA gốc/trung gian bằng hồ sơ “Trusted certificate”. Trên Windows chọn được kho đích (gốc/trung gian máy tính, trung gian người dùng).9

Như 2.1, đưa vào gốc của kho máy tính thì mọi người dùng tin.1 Đúng vì thế hãy nhìn thẳng rủi ro ngược. Vận hành đưa chứng chỉ tự ký vào “Trusted Root Certification Authorities” là hành vi trồng điểm tin cậy mới trên PC đó. Khóa riêng đó rò thì thành bàn đạp phát hành chứng chỉ mạo danh site hay phần mềm tùy ý. Nếu biến thành vận hành lâu dài, hướng đúng là dựng CA nội bộ bảo vệ khóa riêng thích đáng, hoặc kéo sang chứng chỉ CA công cộng; gốc tự ký nguyên tắc là “chỉ môi trường kiểm, cắt hạn”.

7. Góc nhìn nhà phát triển ── dùng kho đúng từ .NET

7.1. Tìm thumbprint bằng X509Store

Từ .NET, mở kho bằng X509Store rồi lấy chứng chỉ bằng Find.1011

using System.Security.Cryptography.X509Certificates;

static X509Certificate2 GetClientCertificate(string thumbprint)
{
    using var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
    store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

    var found = store.Certificates.Find(
        X509FindType.FindByThumbprint, thumbprint, validOnly: true);

    if (found.Count == 0)
        throw new InvalidOperationException(
            $"Không tìm thấy chứng chỉ: thumbprint={thumbprint}, " +
            $"chỗ={store.Location}\\{store.Name}");

    var cert = found[0];
    if (!cert.HasPrivateKey)
        throw new InvalidOperationException(
            $"Có chứng chỉ nhưng khóa riêng chưa gắn (nhập từ .cer" +
            $" chẳng hạn): thumbprint={thumbprint}, chỗ={store.Location}\\{store.Name}");

    return cert;
}

Quyết định Chương 3 nối thẳng vào đây. Mã chạy như dịch vụ thì StoreLocation.LocalMachine; ứng dụng tương tác thì StoreLocation.CurrentUser. Còn một điểm: chú ý đối số thứ ba validOnly của Find. true chỉ trả chứng chỉ hợp lệ đã qua kiểm.11 Đó là bảo hiểm không nắm chứng chỉ hết hạn, nhưng chứng chỉ tự ký kiểm mà chuỗi chưa được tin cũng rơi về phía “không tìm thấy”, nên khi “đã vào mà không tìm thấy” hãy nghi luôn chỗ này. Ngoài ra, thông điệp lỗi khi không tìm thấy hãy luôn ghi đã tìm kho nào, như ví dụ trên. Thời gian điều tra tai nạn Chương 3 đổi cả bậc.

7.2. Gắn chứng chỉ máy khách vào HttpClient

Chứng chỉ đã lấy được thêm vào HttpClientHandler.ClientCertificates rồi trình cho máy chủ. Tập hợp này là tập chứng chỉ trình cho máy chủ trong xác thực máy khách dựa trên chứng chỉ.12

var handler = new HttpClientHandler();
handler.ClientCertificates.Add(GetClientCertificate(thumbprint));

var client = new HttpClient(handler);
// Từ đây dùng như HttpClient thông thường

Ngoài ra trên dòng .NET Core, tài liệu ghi rõ nếu chứng chỉ có thuộc tính Key Usage thì không dùng để gửi yêu cầu trừ khi gồm “Digital Signature”.12 Khi đứng ở vị trí nhờ phát hành chứng chỉ máy khách, hãy truyền đúng mục đích (xác thực máy khách). HttpClient cũng gây cạn socket và lệch DNS nếu sai mẫu tạo. Thiết kế sống lâu cả handler nằm trong “Đừng bọc HttpClient bằng using”.

7.3. Bài toán thumbprint gắn cứng chết lúc thay

Tìm thumbprint thì chắc, nhưng nhúng thumbprint vào mã thì mỗi lần gia hạn chứng chỉ cần build và phát hành. Đối phó từ thiết kế có ba tầng.

  • Tối thiểu: đưa thumbprint ra tệp cấu hình (appsettings, v.v.) để thay mà không cần phát hành. Chỗ cấu hình ghi vào sổ cái 5.3.
  • Tiến một bước: tìm theo tên subject hoặc nhà phát hành, kết hợp validOnly: true rồi chọn “trong những cái đang hợp lệ với tên đó, cái NotAfter xa nhất”. Trong giai đoạn chạy song song cũ-mới sẽ tự chuyển sang chứng chỉ mới. Tuy nhiên có rủi ro nắm chứng chỉ cùng tên ngoài ý muốn, nên ghép kiểm nhà phát hành và ghi nhật ký. Và tự chuyển này chỉ thành khi đối tác không cần đăng ký chứng chỉ trước. Với API cần đăng ký trước (5.2), tự chuyển sang chứng chỉ mới chỉ mới nhập chưa đăng ký có thể dừng giao tiếp, nên hãy dừng ở cách đưa cấu hình ra ngoài rồi chuyển sau khi xác nhận đăng ký xong.
  • Siết bằng vận hành: mọi cách, lúc khởi động hãy ghi nhật ký “đã chọn chứng chỉ nào (thumbprint, hạn)”. Cả điều tra sự cố lẫn đối chiếu sổ cái, một dòng này có hiệu.

8. Quan hệ với chứng chỉ ký mã ── kho “Trusted Publishers”

Đến đây là chứng chỉ cho giao tiếp (TLS), nhưng kho chứng chỉ còn chung sống một thế giới khác ── ký mã. Kho “Trusted Publishers (TrustedPublisher)” trong bảng 2.2 là điểm tiếp xúc, chỗ đăng ký chứng chỉ nhà phát hành phần mềm đã ký như đã tin. Nó tồn tại ở cả chỗ người dùng lẫn máy tính10, dùng cho vận hành kiểu phát chứng chỉ nhà phát hành ứng dụng phân phối nội bộ vào TrustedPublisher của từng PC bằng GPO.

Nếu bạn ở phía “phát” ứng dụng và cần xử lý ký mã hay cảnh báo SmartScreen (“Windows đã bảo vệ PC của bạn”), bài khác “Vì sao Windows hiện ‘Windows đã bảo vệ PC của bạn’” đã gom. Kiến thức bài này (hai hệ kho, phân phối gốc) dùng nguyên như kiến thức tiền đề.

9. Tóm tắt

  • Kho chứng chỉ có hai hệ người dùng (CurrentUser) và máy tính (LocalMachine). certmgr.msc / certlm.msc / ổ Cert: là ba cửa sổ nhìn cùng thứ. Bước đầu điều tra là khớp “đang nói kho nào”.
  • Chỗ đưa vào quyết theo “chương trình chạy với tư cách ai”. Chạy không người (dịch vụ, IIS, tác vụ) thì kho máy tính; ứng dụng tương tác thì nguyên tắc là kho người dùng.
  • “Lúc phát triển thì chạy, sản xuất thì không tìm thấy” vì kho người dùng của nhà phát triển và kho người dùng của tài khoản dịch vụ là hai thứ khác nhau. Khớp kho máy tính + StoreLocation.LocalMachine để giải.
  • Đặt vào kho máy tính và cấp quyền đọc bằng “Manage Private Keys” là một bộ. Đừng quên cấp lại lúc gia hạn.
  • Nhập pfx mặc định không xuất được. -Exportable chỉ khi thật sự cần. Việc lưu pfx gốc và mật khẩu cũng đưa vào thiết kế.
  • Hết hạn ngăn bằng kiểm kê định kỳ Get-ChildItem Cert: ... -ExpiringInDays và sổ cái chứng chỉ. Thay theo thứ tự “thêm → chuyển → xác nhận → xóa”, chú ý sót cập nhật thumbprint trong cấu hình.
  • Khoanh vùng chuỗi bằng certutil -urlfetch -verify. Gốc CA nội bộ phân phối bằng GPO/Intune; vận hành đưa tự ký vào gốc chỉ môi trường kiểm, kèm hạn.
  • Trong mã, đưa thumbprint ra cấu hình và ghi nhật ký chứng chỉ đã chọn. Chỉ thế, ứng phó sự cố do chứng chỉ đổi khác.

Bài viết liên quan

Lĩnh vực tư vấn liên quan

KomuraSoft LLC đảm nhận phát triển ứng dụng nghiệp vụ gắn liên kết Web API kèm chứng chỉ máy khách (API dòng ngân hàng, xác nhận tư cách trực tuyến, v.v.), điều tra sự cố kiểu “không tìm thấy chứng chỉ” / “gia hạn rồi không kết nối được”, và chỉnh quy trình thay chứng chỉ. Tư vấn từ giai đoạn chưa biết kho nào cần nhìn cũng được.

Liên kết tham khảo

  1. Microsoft Learn, Local Machine and Current User Certificate Stores. Về kho chứng chỉ máy tính cục bộ với PC và dùng chung mọi người dùng, nằm dưới HKEY_LOCAL_MACHINE; về kho chứng chỉ người dùng theo tài khoản người dùng, nằm dưới HKEY_CURRENT_USER; về kho người dùng kế thừa nội dung kho máy tính trừ kho “Personal” (chứng chỉ thêm vào “Trusted Root Certification Authorities” của máy tính cũng hiện trên kho cùng tên của từng người dùng).  2 3 4

  2. Microsoft Learn, System Store Locations. Về vị trí registry của CERT_SYSTEM_STORE_CURRENT_USER / CERT_SYSTEM_STORE_LOCAL_MACHINE (lần lượt Software\Microsoft\SystemCertificates dưới HKEY_CURRENT_USER / HKEY_LOCAL_MACHINE); về kho logic định sẵn là MY, Root, Trust, CA; về kho dịch vụ nằm ở khóa registry theo tên dịch vụ (Software\Microsoft\Cryptography\Services\ServiceName\SystemCertificates); về còn có kho riêng cho phân phối Group Policy.  2 3 4 5

  3. Microsoft Learn, How to: View certificates with the MMC snap-in. Về certlm.msc quản chứng chỉ thiết bị cục bộ (máy tính cục bộ), certmgr.msc quản chứng chỉ người dùng hiện tại; về đối tượng snap-in chứng chỉ có ba loại “Computer account”, “User account”, “Service account”; về người dùng không phải quản trị viên chỉ quản được chứng chỉ tài khoản người dùng của mình.  2 3 4

  4. Microsoft Learn, about_Certificate_Provider. Về ổ Cert: của PowerShell là không gian tên tầng có hai chỗ kho CurrentUser và LocalMachine; về liệt kê kho và chứng chỉ bằng Get-ChildItem; về tham số -ExpiringInDays trả chứng chỉ hết hạn trong số ngày chỉ định (0 thì đã hết hạn); về tham số động như -CodeSigningCert; về hạn nằm ở thuộc tính NotAfter; về chứng chỉ được nhận diện bằng thumbprint.  2 3 4 5 6

  5. Microsoft Learn, How to Modify Private Key Permissions to Support Management Server or Streaming Server. Về quy trình mở “Manage Private Keys” từ snap-in chứng chỉ đối tượng kho chứng chỉ máy tính cục bộ, rồi trên tab “Security” thêm quyền truy cập “Read” cho tài khoản chạy dịch vụ (ví dụ Network Service).  2 3

  6. Microsoft Learn, Import-PfxCertificate. Về Import-PfxCertificate nhập chứng chỉ và khóa riêng từ tệp PFX vào kho chỉ định; về không chỉ định công tắc -Exportable thì khóa riêng đã nhập không xuất được; về cú pháp và ví dụ dùng các tham số -CertStoreLocation, -Password, -FilePath.  2 3

  7. Microsoft Learn, certutil. Về certutil -verify kiểm chứng chỉ, CRL, chuỗi chứng chỉ, không chỉ định tệp chứng chỉ CA thì dựng chuỗi đầy đủ rồi kiểm; về tùy chọn -urlfetch dùng được; về certutil -store dump kho chứng chỉ, tùy chọn -user truy cập kho người dùng thay vì kho máy tính.  2

  8. Microsoft Learn, Distribute Certificates to Client Computers by Using Group Policy. Về quy trình nhập chứng chỉ vào “Trusted Root Certification Authorities” dưới Computer Configuration\Policies\Windows Settings\Security Settings\Public Key Policies của Group Policy để phân phối tới máy tính khách trong miền, và quyền cần thiết (tương đương Domain Admins / Enterprise Admins). 

  9. Microsoft Learn, Create trusted certificate profiles in Microsoft Intune. Về hồ sơ “Trusted certificate” của Intune là cơ chế phân phối chứng chỉ CA gốc hoặc trung gian tới thiết bị được quản; về dùng để thiết lập tin CA gốc như tiền đề của hồ sơ chứng chỉ SCEP/PKCS; về Windows chọn được kho đích “Computer certificate store - Root”, “Computer certificate store - Intermediate”, “User certificate store - Intermediate”. 

  10. Microsoft Learn, X509Store Class. Về X509Store dựng được bằng chỉ định StoreName và StoreLocation (CurrentUser / LocalMachine), mở kho bằng phương thức Open và OpenFlags (ReadOnly, OpenExistingOnly, v.v.), lấy tập hợp chứng chỉ bằng thuộc tính Certificates; về tên kho chuẩn gồm My, Root, CA, TrustedPublisher, v.v., kho TrustedPublisher tồn tại ở cả CurrentUser lẫn LocalMachine.  2

  11. Microsoft Learn, X509Certificate2Collection.Find(X509FindType, Object, Boolean) Method. Về phương thức Find tìm chứng chỉ bằng X509FindType (FindByThumbprint, v.v.) và giá trị tìm; về chỉ định true cho đối số thứ ba validOnly thì chỉ trả chứng chỉ hợp lệ đã qua kiểm.  2

  12. Microsoft Learn, HttpClientHandler.ClientCertificates Property. Về thuộc tính ClientCertificates là X509CertificateCollection trình cho máy chủ trong xác thực máy khách dựa trên chứng chỉ; về .NET Core, nếu chứng chỉ có thuộc tính Key Usage thì cần gồm “Digital Signature”.  2

Các bài viết gần đây có cùng thẻ để tìm hiểu sâu hơn những chủ đề lân cận.

Các trang này đặt chủ đề trong bối cảnh rộng hơn của dịch vụ và quyết định.

Bài viết liên quan trực tiếp đến các dịch vụ sau.

Câu hỏi thường gặp

Các câu hỏi thường gặp khi tư vấn về chủ đề của bài viết.

certmgr.msc và certlm.msc khác nhau thế nào?
Kho đối tượng khác nhau. certmgr.msc mở kho chứng chỉ của người dùng đang đăng nhập (người dùng hiện tại, CurrentUser); certlm.msc mở kho chứng chỉ của máy tính (máy tính cục bộ, LocalMachine). Kho máy tính dùng chung cho mọi người dùng và dịch vụ trên PC, và quản lý cần quyền quản trị viên. Người dùng không phải quản trị viên chỉ quản được kho người dùng của mình. Cả hai đều chia thành kho logic như "Personal", "Trusted Root Certification Authorities"; từ PowerShell cùng cấu trúc hiện như Cert:\CurrentUser và Cert:\LocalMachine.
Chứng chỉ máy khách nên vào kho người dùng hay kho máy tính?
Quyết theo chương trình dùng chứng chỉ đó chạy "với tư cách ai". Ứng dụng desktop do người dùng tương tác khởi động thì kho người dùng của đúng người đó (Cert:\CurrentUser\My) là cơ bản. Chương trình chạy không người qua dịch vụ Windows, IIS application pool, Task Scheduler thì đưa vào kho máy tính (Cert:\LocalMachine\My) rồi cấp quyền đọc khóa riêng cho tài khoản chạy. Kho người dùng là thứ khác nhau theo tài khoản, nên chứng chỉ nhà phát triển đưa vào kho người dùng của mình thì dịch vụ chạy bằng tài khoản khác không thấy. Đó là nguyên nhân điển hình của tai nạn "lúc phát triển thì chạy, lên sản xuất thì không tìm thấy".
Khi dịch vụ Windows không thấy hoặc không dùng được chứng chỉ, nên kiểm gì?
Xác nhận hai tầng. Thứ nhất "đang nhìn kho nào". Nếu mã mở StoreLocation.CurrentUser, đó là kho người dùng của tài khoản chạy dịch vụ, khác kho của chính bạn mà quản trị viên đang xem bằng certmgr.msc. Chuyển chứng chỉ sang kho máy tính và khớp mã sang StoreLocation.LocalMachine. Thứ hai "đọc được khóa riêng không". Thấy trong danh sách chứng chỉ và dùng được khóa riêng là hai chuyện; khóa riêng trên kho máy tính thường mặc định chỉ quản trị viên và SYSTEM truy cập được. Từ certlm.msc, mở "Manage Private Keys" trên chứng chỉ đích rồi cấp "Read" cho tài khoản chạy dịch vụ (NETWORK SERVICE, v.v.).
Làm sao phát hiện trước hạn chứng chỉ bằng PowerShell?
Kiểm kê bằng Get-ChildItem trên ổ Cert:. Ví dụ Get-ChildItem Cert:\LocalMachine\My | Sort-Object NotAfter | Format-Table Thumbprint, Subject, NotAfter liệt kê kho Personal của kho máy tính theo hạn. Thêm tham số -ExpiringInDays thì chỉ rút chứng chỉ hết hạn trong số ngày chỉ định; 0 thì ra chứng chỉ đã hết hạn. Đưa việc này thành chạy hàng tháng trên mọi máy chủ rồi đối chiếu kết quả với sổ cái chứng chỉ thì gần như chặn được tai nạn kiểu "hết hạn nên sáng không kết nối được".

Hồ sơ tác giả

Trang giới thiệu tác giả bài viết.

Go Komura

Đại diện của KomuraSoft LLC

Chuyên về phát triển phần mềm Windows, tư vấn kỹ thuật và điều tra lỗi, đặc biệt trong các dự án có hệ thống hiện hữu và lỗi khó tái hiện.

Liên kết công khai

Quay lại blog