Loading Now

Giao Thức HTTPS – Tạo Màn Hình Hiển Thị Tình Hình Covid19

Chào mọi người, mình đã quay trở lại, trong bài viết này mình sẽ hướng dẫn các bạn tạo một dự án cực ngầu với Arduino, đó là hiển thị tình hình covid19 trên màn hình LCD. Trước khi bắt tay vào thực hiện, các bạn nên đọc qua bài Tạo ứng dụng báo cáo tình trạng coronavirus trong vòng 2 ngày. Dữ liệu thu thập mình sẽ lấy từ Covid2019 API.

Có điều làm mình phát điên là esp8266 gửi HTTP requests đến các HTTPS web server để đọc API covid19. Đáng ngại đó là esp8266 là một vi xử lý nhúng, một trong những hạn chế của nó là không thiết lập cho bạn kết nối HTTPS về bảo mật bạn sẽ phải tự thiết đặt bằng tay. Nhưng đó cũng là điều tuyệt vời đấy chứ, thay vì gõ đường link trang web vào ô địa chỉ trên trình duyệt bạn sẽ đi tạo một kết nối từ máy tính của bạn với thanh địa chỉ đó. Và đó cũng là điều chúng ta sẽ học được qua dự án này.

Được rồi, chúng tay hãy cùng bắt đầu thực hiện các bước nào.

1. Yêu cầu phần cứng

  • 1 Mạch Module IOT ESP8266 ESP-12E
  • 1 chiếc màn hình, bạn có thể chọn 1 chiếc màn hình LCD 1280
  • 1 cap nối USB 2.0
  • Một ít dây điện để nối con esp8266 của bạn với màn hình
  • 1 Laptop có kết nối mạng.
  • Và có thể một cục adapter từ 5 đến 9v

Tổng chi phí bạn bỏ ra cho dự án này là khoảng 200k, có vẻ đắt nhưng đừng lo, vì bạn có thể thịt nó bất cứ lúc nào bạn muốn.

2. Chuẩn bị kiến thức

Nếu bạn là người mới bắt đầu vào việc học lập trình, khóa học Mạng máy tính sẽ bổ ích với bạn.

Giao thức HTTP là gì?

HTTP (Hypertext Transfer Protocol) là một giao thức ứng dụng của bộ giao thức TCP/IP (các giao thức nền tảng cho Internet). Bộ giao thức TCP/IP là một bộ các giao thức truyền thông cài đặt chồng giao thức mà Internet và hầu hết các mạng máy tính thương mại đang chạy trên đó. Bộ giao thức này được đặt theo tên hai giao thức chính là TCP (Transmission Control Protocol – Giao thức điều khiển truyền vận) và IP (Internet Protocol – Giao thức Internet).

HTTP hoạt động theo mô hình Client (máy khách) – Server (máy chủ). Việc truy cập website được tiến hành dựa trên các giao tiếp giữa 2 đối tượng trên. Khi bạn truy cập một trang web qua giao thức HTTP, trình duyệt sẽ thực hiện các phiên kết nối đến server của trang web đó thông qua địa chỉ IP do hệ thống phân giải tên miền DNS cung cấp. Máy chủ sau khi nhận lệnh, sẽ trả về lệnh tương ứng giúp hiển thị website, bao gồm các nội dung như: văn bản, ảnh, video, âm thanh,…

Giao thức HTTP

Trong quá trình kết nối và trao đổi thông tin, trình duyệt của bạn sẽ mặc nhiên thừa nhận địa chỉ IP đó đến từ server của chính website mà bạn muốn truy cập mà không hề có biện pháp xác thực nào. Các thông tin được gửi đi qua giao thức HTTP (bao gồm địa chỉ IP, các thông tin mà bạn nhập vào website…) cũng không hề được mã hóa và bảo mật. Đây chính là kẽ hở mà nhiều hacker đã lợi dụng để đánh cắp thông tin người dùng, thường được gọi là tấn công sniffing.

Giao thức HTTPS là gì?

HTTPS (Hypertext Transfer Protocol Secure) là giao thức truyền tải siêu văn bản an toàn. Thực chất, đây chính là giao thức HTTP nhưng tích hợp thêm Chứng chỉ bảo mật nhằm mã hóa các thông điệp giao tiếp để tăng tính bảo mật. Có thể hiểu, HTTPS là phiên bản HTTP an toàn, bảo mật hơn.

Các trang HTTPS thường sử dụng một trong hai giao thức bảo mật để mã hóa thông tin liên lạc:

  • SSL (Secure Sockets Layer)
  • TLS (Transport Layer Security)

Cả hai giao thức TLS và SSL đều sử dụng hệ thống PKI (Public Key Infrastructure) không đối xứng. Một hệ thống không đối xứng sử dụng hai “khóa” để mã hóa thông tin liên lạc, khóa “công khai” và khóa “riêng”. Bất cứ thứ gì được mã hóa bằng khoá công khai (public key) chỉ có thể được giải mã bởi khóa riêng (private key) và ngược lại.

HTTP + SSL = HTTPS

SSL là gì?

SSL là viết tắt của Secure Sockets Layer, một công nghệ tiêu chuẩn cho phép thiết lập kết nối được mã hóa an toàn giữa máy chủ web (host) và trình duyệt web (client). Kết nối này đảm bảo rằng dữ liệu được truyền giữa host và client được duy trì một cách riêng tư, đáng tin cậy. Nếu có một cửa hàng online hoặc bán đồ trên website, SSL sẽ giúp tạo lập sự tin tưởng với khách hàng và bảo mật thông tin được trao đổi qua lại giữa bạn với khách hàng.

SSL được phát triển bởi Netscape, ngày nay giao thức SSL đã được sử dụng rộng rãi trên World Wide Web trong việc xác thực và mã hoá thông tin giữa client và server. Tổ chức IETF (Internet Engineering Task Force ) đã chuẩn hoá SSL và đặt lại tên là TLS. Mặc dù là có sự thay đổi về tên nhưng TSL chỉ là một phiên bản mới của SSL. Phiên bản TSL 1.0 tương đương với phiên bản SSL 3.1. Tuy nhiên SSL là thuật ngữ được sử dụng rộng rãi hơn

SSL được thiết kế như là một giao thức riêng cho vấn đề bảo mật có thể hỗ trợ cho rất nhiều ứng dụng. Giao thức SSL hoạt động bên trên TCP/IP và bên dưới các giao thức ứng dụng tầng cao hơn như là HTTP, IMAP và FTP.SSL

SSL không phải là một giao thức đơn lẻ, mà là một tập các thủ tục đã được chuẩn hoá để thực hiện các nhiệm vụ bảo mật sau:

  • Xác thực server: Cho phép người sử dụng xác thực được server muốn kết nối. Lúc này, phía browser sử dụng các kỹ thuật mã hoá công khai để chắc chắn rằng certificate và public ID của server là có giá trị và được cấp phát bởi một CA (certificate authority) trong danh sách các CA đáng tin cậy của client.
  • Xác thực Client: Cho phép phía server xác thực được người sử dụng muốn kết nối. Phía Client cũng sử dụng các kỹ thuật mã hoá công khai để kiểm tra xem certificate và public ID của server có giá trị hay không và được cấp phát bởi một CA (certificate authority) trong danh sách các CA đáng tin cậy của Client không.
  • Mã hoá kết nối: Tất cả các thông tin trao đổi giữa client và server được mã hoá trên đường truyền nhằm nâng cao khả năng bảo mật.

Để kiểm tra  CA của một trang web, ấn vào biểu tượng ổ khóa trên thanh địa chỉ và chọn vào Chứng chỉ, bạn sẽ đọc được CA của trang web đó.

CA của Codelearn

Do giới hạn của bài viết mình chỉ đề cập đến việc tạo một kết nối tới địa chỉ HTTPS, mình sẽ kết thúc phần kiến thức về mạng ở đây, các phần dưới là các kiến thức về phần cứng bạn cần biết để thực hiện được dự án này.

SPIFFS quản lý file system cho esp8266

Bạn sẽ bất ngờ khi biết rằng esp8266 cho phép bạn phân vùng bộ nhớ flash của nó vừa để upload code lên vừa hỗ trợ lưu trữ một hệ thống tập tin. SPIFFS viết tắt của SPI Flash Filing System, nó được thiết kế cho SPI Flash device với chip vi xử lý có RAM rất nhỏ.

Ở phần tiếp theo, bạn sẽ cần lưu trữ một vài CA để thực hiện giao thức HTTPS, việc mua thêm một module SD card để sử dụng thẻ nhớ lưu trữ theo mình là không cần thiết, sử dụng SPIFFS sẽ làm nhỏ gọn hơn về phần điện của dự án và mình cũng muốn thử thêm một cách lưu trữ mới.

Để thực hiện upload data file bằng SPIFFS thì bạn cần cài đặt plugin ESP8266FS mới nhất, giải nén ra và copy tool .jar vào đường dẫn C:\Program Files (x86)\Arduino\tools\ESP8266FS\tool

Có một tài liệu khá hay về việc cài đặt và các công cụ cho bạn sử dụng SPIDFFS trên arduino ở instructables.com

Chú ý:

  • Nếu bạn không upload được folder data lên bằng SPIFFS, hãy tải tool ESP8266FS mới nhất, cập nhập arduino bản mới nhất và update board esp8266 mới nhất ở board manage.
  • Khi các bạn upload data lên bằng SPIFFS cho esp8266, nhớ ấn giữ nút Flash của nó từ trước khi upload cho tới khi hoàn thành.

3. Chuẩn bị CA cho kết nối HTTPS

Nếu bạn chưa cài đặt được các công cụ cần thiết để lập trình Arduino hãy xem qua 2 trang sau:

Mình đã lục tung cả Google lên để tìm các code kết nối esp8266 với HTTPS và hầu như đoạn code mà mình có thể tìm đều chỉ định certificate fingerprint để xác thực CA của máy chủ. Điều tồi tệ là fingerprint sẽ thay đổi khi certificate được gia hạn. Mình không muốn phải thay cái fingerprint vì sẽ phải sửa lại code. Tìm kiếm một cách tốt hơn, mình tình cờ thấy thư viện BearSSl cho arduino, nó sẽ sử dụng các CA được lưu trữ trong máy kết nối thông qua ESP8266HTTPClient  kết thừa lớp WiFiClientSecure. Nhưng việc lắp ráp các đoạn code của BearSSL đã làm code của chương trình arduino của mình rất ngắn và cũng có phần đơn giản quá.

Trở lại với dự án, hãy đi thu thập các CA từ Mozilla. Bạn sẽ có bộ kho chứng chỉ gốc Mozilla, điều đó có nghĩa là thiết bị của bạn có thể thực hiện các yêu cầu SSL giống như trong trình duyệt, với các chứng chỉ được tự động kiểm tra đối với danh sách CA mà Mozilla tin tưởng.

Hãy chuẩn bị đầu tiên, thu thập cert từ Mozilla. Bạn có thể chạy một code python sau, nó sẽ tự động thu thập CA về và tạo một file tên là “cert.ar” trong một thư mục data . Hãy giữ thư mục data đó và paste vào sketch trong project arduino của bạn.

Bạn có thể xem thêm về BearSSL.

Chú ý: nếu bạn dùng window hãy chạy code python trên https://repl.it/languages/python3 và tải thư mục data về.

4. Bắt tay vào code

Hãy tạo một sketch mới, lưu lại và nhớ copy folder data bạn đã lưu các CA ở bên trên bỏ vào sketch mới tạo đó.

Mình sẽ cần khai báo một vài thư viện cần dùng.

#include <ESP8266WiFi.h>          // tạo kết nối với wifi
#include <ESP8266HTTPClient.h>    // tạo kết nối client tới web server
#include <WiFiClientSecure.h>     // lớp bảo mật
#include <CertStoreBearSSL.h>     // Bạn cần thêm để đọc được gói CA đã lưu trong flash
#include <LiquidCrystal_I2C.h>    // Hiển thị màn hình LCD I2C
#include <FS.h>                   // thư viện SPIFFS cho esp8266
#include <String>                 // xử lý data

Trước khi xây dựng các hàm, mình sẽ tạo ra một vài biến để chương trình sử dụng.

char ssid[] = "";       // tên wifi
char password[] = "";  // mật khẩu

char HOST_NCOV[] = "https://api.covid19api.com/summary";
String TOTAL_STRING = "TotalConfirmed";
String DEATH_STRING = "TotalDeaths";
String RECOVER_STRING = "TotalRecovered";

String Totals = "";
String Deaths = "";
String Recovers = "";

Để xác nhận CA của server, bạn cần đồng bộ hóa thời gian đang chạy của esp8266 bằng NTP, đây là yêu cầu bắt buộc cho các kết nối SSL. Mình sẽ tạo ra một đoạn mã ngắn để đồng bộ hóa thời gian GMT +7.

void setClock() {
  configTime(7 * 3600, 0, "pool.ntp.org", "time.nist.gov");
//configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  Serial.print("Waiting for NTP time sync: ");
  time_t now = time(nullptr);  
  while (now < 8 * 3600 * 2) {  // while (!time(nullptr))
    delay(500);
    Serial.print(".");
    now = time(nullptr);
  }
  Serial.println("");
  struct tm timeinfo;
  gmtime_r(&now, &timeinfo);     
  Serial.print("Current time: ");
  Serial.print(asctime(&timeinfo));
}

Trong hàm Setup, mình sẽ thiết lập một vài thông số trước khi kết nối

void setup() {
  lcd.begin();
  lcd.backlight();
  lcd.print("Hello, world!");  
// kết thúc khởi tạo LCD
  Serial.begin(115200);  
  Serial.println(".");
  Serial.println(".");
// kết thúc khởi tạo serial để debug
  SPIFFS.begin();  // bật SPIFFS
  int numCerts = certStore.initCertStore(SPIFFS, PSTR("/certs.idx"), PSTR("/certs.ar"));
  Serial.print(F("Number of CA certs read: "));
  Serial.println(numCerts);
  if (numCerts == 0) {
    Serial.println(F("No certs found. Did you run certs-from-mozill.py and upload the SPIFFS directory before running?"));
    return; // Can't connect to anything w/o certs!
  }
// Hoàn thành việc đọc các CA lưu trữ trong SPIFFS

  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);
  // Bắt đầu kết nối
  Serial.print("Connecting Wifi: ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) 
  {
    Serial.print(".");
    delay(500);
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  IPAddress ip = WiFi.localIP();
  Serial.println(ip);
// kết nối wifi xong
}

Trong hàm loop, mình sẽ kết nối với HTTPS với thư viện BearSSL, mình sẽ để vòng loop chạy cứ mỗi 20 phút để tránh bị server chặn kết nối.

void loop()
{
  setClock();   // đồng bộ thời gian   
  
  HTTPClient http;  // khởi tạo kết nối Client-> web server
  BearSSL::WiFiClientSecure *client = new BearSSL::WiFiClientSecure(); // biến client kế thừa lớp WiFiClientSecure
  client->setCertStore(&certStore); // lưu các CA
  http.begin(dynamic_cast<WiFiClient&>(*client), HOST_NCOV); // kết nối HTTPS
  int httpCode = http.GET();  // đọc mã trạng thái
  if (httpCode > 0)
 {
     String s = http.getString();
     Serial.print("Data length: ");
     Serial.println(s.length());
     int n = s.length();
     printResult();
 }
 delay(20*60*1000);
}

Cuối cùng là hàm hiển thị ra màn hình, chuỗi kết quả s của mình là json khá dài, mình sẽ sử dụng một cách đơn giản để 

void printResult()
//  Serial.println(s.indexOf(TOTAL_STRING));
  for(int i=s.indexOf(TOTAL_STRING)+TOTAL_STRING.length();i<s.indexOf(TOTAL_STRING)+30;i++)
  {
    if (s[i] != '"')
      Totals += s[i];
    if (s[i] == ',')
    {
      break;
    }
  }
//  Serial.println(s.indexOf(DEATH_STRING));
  for(int i=s.indexOf(DEATH_STRING)+DEATH_STRING.length();i<s.indexOf(DEATH_STRING)+30;i++)
  {
    if (s[i] != '"')
      Deaths+= s[i];
    if (s[i] == ',')
    {
      break;
    }
  }
  lcd.setCursor(0, 0);
  lcd.print("Totals");
  lcd.print(Totals);
  lcd.setCursor(0, 1);
  lcd.print("Deaths");
  lcd.print(Deaths);
  lcd.display();
}

Và đây là kết quả của mình, esp8266 sẽ kết nối tới wifi rồi cuối cùng là hiển thị tình hình covid19 lên trên màn hình.

5. Kết luận

Qua dự án trên, bạn sẽ thấy việc truy cập vào các API bằng HTTPS sẽ trở lên đơn giản vô cùng. Bước phát triển tiếp theo của sản phẩm, bạn hãy thử code lại phần hiển thị kết quả trên hoặc thay luôn bằng một chiếc màn hình mới và đẹp hơn, tìm cách sử dụng esp8266 để đăng nhập vào các trang web bằng user và password…

Hẹn gặp lại các bạn trong các bài sắp tới.

Post Comment

Contact