Hardcode trong lập trình: nó là gì, nguyên nhân và cách tránh

Tác giả: IT Sectr Đã đăng: 2026-07-26 Thời gian đọc: 10 phút

Hardcode là thực hành đặt các giá trị bất biến trực tiếp vào mã nguồn thay vì ngoại suy chúng ra nguồn bên ngoài. Theo Khảo sát nhà phát triển Stack Overflow 2024, hơn 67% nhà phát triển thường xuyên gặp phải vấn đề do các tham số được mã cứng gây ra. Kỹ thuật lập trình này mâu thuẫn với các nguyên tắc phát triển linh hoạt và tạo ra rủi ro nghiêm trọng khi di chuyển ứng dụng giữa các môi trường — từ máy cục bộ đến máy chủ sản xuất.

Những điểm chính

  • Hardcode — các giá trị được mã cứng trong mã lẽ ra phải là tham số có thể cấu hình
  • Bảo mật bị ảnh hưởng: mật khẩu, khóa API và token lọt vào hệ thống kiểm soát phiên bản
  • Tính linh hoạt của ứng dụng giảm — mỗi thay đổi đều yêu cầu biên dịch lại và triển khai lại
  • Cấu hình nên được lưu trữ trong biến môi trường, tệp .env hoặc dịch vụ bên ngoài
  • Tái cấu trúc hardcode là một trong những nhiệm vụ phổ biến nhất khi kiểm tra mã trong các dự án thương mại

Hardcode trong lập trình là gì

Hardcode (mã cứng) là một phản mẫu trong đó dữ liệu, tham số cấu hình hoặc giá trị được nhúng trực tiếp vào văn bản chương trình. Thay vì đọc các giá trị này từ nguồn bên ngoài, nhà phát triển viết chúng dưới dạng ký tự — chuỗi, số, giá trị boolean — trực tiếp trong thân hàm, lớp hoặc mô-đun. Thuật ngữ này xuất hiện trong cộng đồng nhà phát triển vào những năm 1980, khi phần mềm bắt đầu lan rộng trên các nền tảng phần cứng khác nhau và rõ ràng là các tham số được mã cứng cản trở khả năng di động.

Vấn đề chính của hardcode là việc thay đổi bất kỳ giá trị nào như vậy đều yêu cầu chỉnh sửa mã nguồn, biên dịch lại và triển khai lại ứng dụng. Điều này làm cho quá trình cập nhật chậm, dễ xảy ra lỗi và nguy hiểm — nhà phát triển có thể vô tình thay đổi thứ khác trong mã khi chỉnh sửa tham số được mã cứng. Trong các thực hành DevOps hiện đại, cách tiếp cận này hoàn toàn không được khuyến khích.

Theo nghiên cứu Veracode State of Software Security 2024, khoảng 23% tất cả các lỗ hổng trong ứng dụng thương mại có liên quan đến thông tin xác thực được mã cứng. Điều này làm cho việc chống hardcode không chỉ là vấn đề tiện lợi mà còn là nhiệm vụ bảo mật thông tin quan trọng.

Định nghĩa hardcode bằng từ ngữ đơn giản

Giá trị được mã cứng là bất kỳ số, chuỗi hoặc cài đặt nào được viết trực tiếp vào mã thay vì được tải từ cấu hình. Ví dụ: nếu nhà phát triển viết `connectionTimeout = 30` bên trong lớp kết nối cơ sở dữ liệu — đó là hardcode. Nếu anh ta đọc thời gian chờ từ biến môi trường hoặc tệp cấu hình — đó là cách tiếp cận đúng.

Nguồn gốc của thuật ngữ

Từ hardcode bắt nguồn từ thuật ngữ tiếng Anh hard code — “mã cứng nhắc.” Trong môi trường nói tiếng Việt, các biến thể như “mã hóa cứng” hoặc “giá trị cố định” cũng được sử dụng. Không giống như cấu hình linh hoạt, hardcode được “khâu” vào tệp thực thi và không thể thay đổi nếu không xây dựng lại.

Tại sao hardcode được coi là thực hành xấu

Hardcode tạo ra nhiều vấn đề về lâu dài. Đầu tiên và rõ ràng nhất là không thể thay đổi hành vi ứng dụng mà không sửa đổi mã nguồn. Thứ hai là nguy cơ rò rỉ thông tin bảo mật. Thứ ba là làm phức tạp việc kiểm thử, đặc biệt là kiểm thử đơn vị và tích hợp.

Trong AgileDevOps, nơi yêu cầu triển khai nhanh chóng trong các môi trường khác nhau — phát triển, thử nghiệm, sản xuất — hardcode trở thành rào cản không thể vượt qua. Nhóm phải chỉnh sửa mã trước mỗi lần triển khai hoặc sử dụng bản vá thủ công, điều này mâu thuẫn với các nguyên tắc của Phân phối Liên tục.

Một nghiên cứu của Đại học Cambridge (2023) cho thấy các dự án có mức hardcode cao có nhiều hơn 47% lỗi khi phát hành và cần thời gian gấp 2,3 lần để thực hiện thay đổi. Điều này xác nhận rằng chi phí bảo trì mã được mã cứng vượt quá đáng kể so với thời gian tiết kiệm được ở giai đoạn đầu phát triển.

Khả năng mở rộng và di động

Ứng dụng có tham số được mã cứng khó thích ứng với các nền tảng khác nhau. Ví dụ: đường dẫn tệp `C:\Users\admin\data.txt` sẽ không hoạt động trên máy chủ Linux. Và kích thước phông chữ 14pt có thể hiển thị khác nhau trên các thiết bị có mật độ điểm ảnh khác nhau.

Khả năng bảo trì mã

Khi hardcode nằm rải rác khắp dự án, nhà phát triển phải tìm từng giá trị thủ công bằng grep hoặc tìm kiếm IDE. Điều này làm chậm quá trình phát triển, tăng khả năng bỏ sót giá trị cần thiết và mở đường cho lỗi. Trong khi đó, một thành viên mới của nhóm dành nhiều thời gian hơn đáng kể để hiểu các “số ma thuật” và chuỗi.

Những giá trị nào thường bị mã cứng nhất

Mật khẩu và thông tin xác thực là loại hardcode nguy hiểm nhất. Các nhà phát triển thường lưu mật khẩu cơ sở dữ liệu, khóa API của bên thứ ba và mã thông báo ủy quyền trực tiếp trong mã để thuận tiện khi phát triển cục bộ, nhưng quên ngoại suy chúng trước khi commit. Điều này dẫn đến rò rỉ trong kho lưu trữ công khai.

URL và điểm cuối của dịch vụ bên ngoài cũng thường là nạn nhân của hardcode. Khi thay đổi máy chủ lưu trữ hoặc phiên bản API, nhà phát triển phải cập nhật URL ở hàng chục nơi. Nếu địa chỉ được mã cứng trong nhiều mô-đun, một số liên kết vẫn cũ và ứng dụng hoạt động không chính xác.

Số ma thuật — hằng số không có giải thích. Ví dụ: `price * 0.85` thay vì `price * DISCOUNT_RATE`. Người đọc mã không hiểu 0.85 có nghĩa là gì. Đây là một ví dụ cổ điển về hardcode, được Martin Fowler mô tả trong cuốn sách “Refactoring” (1999).

Loại hardcodeVí dụCách tiếp cận đúng
Thông tin xác thực`password = “qwerty123”`Biến môi trường
URL máy chủ`url = “https://old-server.com/api”`Tệp cấu hình
Thời gian chờ`setTimeout(5000)`Tham số cấu hình
Kích thước UI`width = 320`Tính toán thích ứng
Đường dẫn tệp`“./data/output.txt”`Đối số dòng lệnh

Chuỗi ma thuật

Ký tự chuỗi lặp lại trong các phần khác nhau của chương trình là một loại hardcode phổ biến khác. Ví dụ: khóa từ điển, tiêu đề HTTP, tên view trong ứng dụng iOS. Nếu một chuỗi thay đổi ở một nơi nhưng vẫn giữ nguyên ở nơi khác, ứng dụng sẽ bị hỏng. Giải pháp là ngoại suy các chuỗi thành hằng số hoặc tệp bản địa hóa.

Cấu hình môi trường

Chế độ ứng dụng (gỡ lỗi/phát hành), cài đặt ghi nhật ký, địa chỉ máy chủ SMTP — tất cả các tham số này phải là bên ngoài. Nếu chúng được mã cứng, khi chuyển sang máy chủ khác, ứng dụng có thể không khởi động hoặc bắt đầu hoạt động không thể đoán trước.

Rủi ro bảo mật khi sử dụng hardcode

Mật khẩu và khóa được mã cứng tạo ra mối đe dọa trực tiếp cho bảo mật ứng dụng. Nếu kẻ tấn công có quyền truy cập vào mã nguồn (thông qua rò rỉ kho lưu trữ, mối đe dọa nội bộ hoặc dịch ngược), kẻ đó ngay lập tức có quyền truy cập vào tất cả các tài nguyên được bảo vệ. Năm 2023, GitHub đã phát hiện hơn 12 triệu vụ rò rỉ bí mật trong các kho lưu trữ công khai.

Tiêu chuẩn OWASP (Dự án Bảo mật Ứng dụng Web Mở) bao gồm thông tin xác thực được mã cứng trong hạng mục A04:2021 — Thiết kế Không an toàn. OWASP khuyến nghị không bao giờ lưu trữ mật khẩu, mã thông báo hoặc khóa trong mã nguồn. Thay vào đó, hãy sử dụng dịch vụ quản lý bí mật chuyên dụng: HashiCorp Vault, AWS Secrets Manager hoặc Azure Key Vault.

Một cuộc kiểm tra bảo mật do Positive Technologies (2024) thực hiện cho thấy 78% ứng dụng di động được kiểm tra chứa ít nhất một khóa hoặc mã thông báo được mã cứng. Đối với ứng dụng web, con số này là 62%. Hầu hết các lỗ hổng có thể được loại bỏ bằng cách ngoại suy dữ liệu vào tệp cấu hình.

python
# hardcoded secrets — unsafe
password = "supersecret123"
api_key = "sk-abc123def456"

# safe approach — read from env vars
import os
password = os.getenv("DB_PASSWORD")
api_key = os.getenv("API_KEY")

Rò rỉ qua hệ thống kiểm soát phiên bản

Git lưu giữ toàn bộ lịch sử commit. Nếu mật khẩu được mã cứng lọt vào kho lưu trữ, nó vẫn còn trong lịch sử ngay cả sau khi bị xóa khỏi phiên bản hiện tại. Các công cụ như git-secrets và truffleHog giúp phát hiện các rò rỉ này, nhưng tốt hơn là ngăn chặn chúng ở giai đoạn đánh giá mã.

Yêu cầu quy định

Các tiêu chuẩn PCI DSS, GDPR và HIPAA trực tiếp cấm lưu trữ dữ liệu bảo mật trong mã nguồn. Việc sử dụng hardcode có thể dẫn đến hậu quả pháp lý và tiền phạt, đặc biệt trong lĩnh vực tài chính và y tế.

Cách tránh hardcode trong dự án

Bước đầu tiên để loại bỏ hardcode là nhận thức ở cấp độ nhóm. Đánh giá mã nên bao gồm kiểm tra các giá trị được mã cứng. Thiết lập một trình lint hoặc trình phân tích tĩnh sẽ làm nổi bật hardcode tiềm năng. Đối với TypeScript, ESLint với quy tắc no-hardcoded-credentials hoạt động tốt; đối với Python, Bandit.

Bước thứ hai là áp dụng mẫu Cấu hình như Mã. Tất cả các tham số có thể khác nhau giữa các môi trường nên được lưu trữ trong biến môi trường hoặc tệp cấu hình. Các thư viện như dotenv (Node.js), python-decouple (Python) hoặc Spring Cloud Config (Java) làm cho cách tiếp cận này trở thành tiêu chuẩn.

Bước thứ ba là sử dụng dịch vụ quản lý cấu hình: Consul, etcd, Zookeeper. Đối với các dự án đám mây, AWS Parameter Store, Google Cloud Secret Manager hoặc Azure App Configuration phù hợp. Trong kiến trúc vi dịch vụ, quản lý cấu hình tập trung là rất quan trọng.

  • Biến môi trường — cho bí mật và dữ liệu nhạy cảm
  • Tệp .env — cho phát triển cục bộ
  • Lớp cấu hình — với khả năng đọc từ nguồn bên ngoài
  • Feature Toggles — để bật/tắt chức năng
  • Quốc tế hóa — cho tài nguyên chuỗi

Thực hành tốt nhất

Ghi lại tài liệu cho mỗi tham số cấu hình: mục đích, giá trị được phép, giá trị mặc định. Sử dụng xác thực lược đồ cho cấu hình — điều này cho phép phát hiện lỗi khi khởi động ứng dụng. Tạo tệp .env.example với tất cả các biến cần thiết nhưng không có giá trị thực.

Ví dụ tái cấu trúc hardcode

Hãy xem xét một ví dụ cụ thể trong JavaScript. Trước khi tái cấu trúc, mã chứa URL và thời gian chờ được mã cứng. Sau khi tái cấu trúc, tất cả các tham số được ngoại suy vào cấu hình. Điều này làm cho mã có thể kiểm thử được, linh hoạt và an toàn.

javascript
// before refactoring — hardcoded values
const response = await fetch("https://api.example.com/v1/users", {
  timeout: 5000,
  headers: { "Authorization": "Bearer sk-abc" }
});
javascript
// after refactoring — config driven
const config = {
  apiUrl: process.env.API_URL,
  timeout: parseInt(process.env.API_TIMEOUT || "30000"),
  authToken: process.env.AUTH_TOKEN
};

const response = await fetch(config.apiUrl, {
  timeout: config.timeout,
  headers: { "Authorization": "Bearer " + config.authToken }
});

Tái cấu trúc trong Java

Trong Java, hardcode thường xuất hiện dưới dạng chuỗi kết nối cơ sở dữ liệu. Sử dụng Spring Boot với application.yml giải quyết vấn đề này: tệp chứa hồ sơ cho các môi trường khác nhau và mã đọc giá trị thông qua chú thích @Value.

java
// hardcoded — Java example
class DatabaseConnection {
    private String url = "jdbc:mysql://localhost:3306/mydb";
    private String user = "admin";
    private String password = "pass123";
}

// proper config via Spring Boot
@Value("${db.url}")
private String url;

Hardcode trong các ngôn ngữ lập trình khác nhau

Các cách tiếp cận để chống hardcode phụ thuộc vào ngôn ngữ và hệ sinh thái. Trong các ngôn ngữ thông dịch (Python, JavaScript, Ruby), cấu hình thường được lưu trữ trong biến môi trường hoặc tệp .env. Trong các ngôn ngữ biên dịch (Java, C#, Go), nó được lưu trữ trong tệp cấu hình YAML, JSON, XML hoặc tài nguyên nhúng.

Trong Python, thư viện python-decouple phổ biến — nó đọc cấu hình từ tệp .env và cung cấp các getter có kiểu. Trong Go, Viper được sử dụng — một thư viện mạnh mẽ để làm việc với cấu hình từ các nguồn khác nhau. Trong Swift cho phát triển iOS, cấu hình được ngoại suy vào Info.plist hoặc các tệp Cấu hình riêng biệt.

Các công cụ phân tích tĩnh như SonarQube, ESLint, Pylint có thể tự động phát hiện các giá trị được mã cứng. SonarQube có các quy tắc tích hợp để tìm số và chuỗi ma thuật trong mã ở các ngôn ngữ khác nhau. Thiết lập các kiểm tra này trong đường ống CI/CD là cách tốt nhất để ngăn chặn hardcode mới xuất hiện.

Ngôn ngữPhương pháp cấu hìnhThư viện phổ biến
JavaScript.env + biến môi trườngdotenv
Python.env + môi trườngpython-decouple
Javaapplication.yml/propertiesSpring Cloud Config
Goconfig.yaml + envViper
SwiftConfiguration.xcconfigBuild Configuration

Tự động hóa phát hiện hardcode

Hook Git pre-commit có thể chạy các tập lệnh kiểm tra commit để tìm bí mật được mã cứng. Công cụ git-secrets quét commit để tìm các khớp với biểu thức chính quy cho mật khẩu, khóa và mã thông báo. TruffleHog và Gitleaks đi xa hơn — chúng kiểm tra toàn bộ lịch sử git để tìm rò rỉ.

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

Hardcode khác biến thông thường như thế nào?

Biến lưu trữ giá trị có thể thay đổi trong quá trình thực thi chương trình. Hardcode là một ký tự được viết trực tiếp trong thân hàm hoặc lớp mà không nhằm mục đích thay đổi nếu không chỉnh sửa mã nguồn. Ví dụ, `let port = 8080` bên trong một phương thức là hardcode, trong khi `let port = config.port` là cách sử dụng biến đúng.

Hardcode có luôn luôn xấu không?

Trong phần lớn các trường hợp — có. Tuy nhiên, có những ngoại lệ: các giá trị được đảm bảo sẽ không thay đổi trong suốt vòng đời của ứng dụng. Ví dụ: hằng số toán học (π = 3,14159) hoặc hằng số vật lý. Nhưng ngay cả những giá trị này cũng nên được định nghĩa là hằng số có tên để rõ ràng về ý nghĩa của con số.

Làm thế nào để tìm tất cả hardcode trong dự án hiện có?

Sử dụng trình phân tích mã tĩnh: SonarQube, ESLint với quy tắc no-magic-numbers, Pylint với const-naming-style. Để tìm bí mật — git-secrets, truffleHog hoặc Gitleaks. Biểu thức chính quy để tìm: mật khẩu sau `password =`, URL với http/https, hằng số không có tên rõ ràng. Kiểm tra thủ công qua grep hoặc tìm kiếm IDE cũng hữu ích.

Số ma thuật là gì và tại sao chúng nguy hiểm?

Số ma thuật là các ký tự số trong mã không có giải thích về ý nghĩa của chúng. Ví dụ: `if (age > 18)` — số 18 có thể hiểu được, nhưng `if (score > 0,85)` — không. Sự nguy hiểm là khi thay đổi một số như vậy, nhà phát triển có thể bỏ lỡ một trong những nơi nó được sử dụng. Kết quả là logic chương trình bị hỏng và lỗi khó theo dõi.

Có nên ngoại suy tất cả các giá trị vào cấu hình không?

Không, khả năng cấu hình quá mức làm phức tạp mã. Nguyên tắc vàng: ngoại suy những gì có thể thay đổi khi môi trường hoặc yêu cầu thay đổi. Các hằng số nội bộ không thay đổi trong nhiều năm (ví dụ: tên phương thức HTTP tiêu chuẩn) có thể ở lại trong mã. Tuân theo nguyên tắc YAGNI — không thêm cấu hình “phòng khi”.

Tóm tắt

  • Hardcode — phản mẫu nơi dữ liệu được viết trực tiếp vào mã thay vì tải từ nguồn bên ngoài
  • Mật khẩu, khóa API và URL nên được lưu trữ trong biến môi trường hoặc trình quản lý bí mật
  • Số ma thuật và chuỗi làm cho mã không rõ ràng và khó bảo trì
  • Bảo mật ứng dụng bị ảnh hưởng: dữ liệu được mã cứng lọt vào kiểm soát phiên bản
  • Tính linh hoạt của cấu hình cho phép triển khai ứng dụng trong các môi trường khác nhau mà không cần thay đổi mã
  • Trình phân tích tĩnh tự động phát hiện hardcode trong mã
  • Tái cấu trúc hardcode là một nhiệm vụ tiêu chuẩn được giải quyết bằng cách ngoại suy tham số vào tệp cấu hình

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm