bookmark_borderMySQL issue – Type conversion – Bug or Feature?

Nay gặp một bug security củ chuối liên quan đến Laravel và MySQL.

Như mọi người đều biết thì hầu hết các framework hiện nay thằng nào cũng truy vấn CSDL dựa trên Query Builder thay vì phải viết raw query như hồi xưa. Một lợi ích của nó là cung cấp 1 phương thức giúp các dev binding dữ liệu vào câu query được an toàn. Nhưng cũng chính vì thế mà Query Builder trở thành 1 cái blackbox. Dev viết truy vấn CSDL bằng Query Builder mà không cần biết câu raw query thằng Builder đó sinh ra sẽ như thế nào (trừ những lúc cần thiết lắm thì mới phải trace debug xem hình thù nó ra làm sao). Và điều đó vô tình dẫn đến mấy cái lỗi trời ơi đất hỡi mà nếu không “ngẫu nhiên” được “trải nghiệm” thử thì cũng chẳng biết nó tồn tại.

Bắt đầu với câu truy vấn đơn giản như sau, khi muốn lấy ra record trong bảng usersid bằng 1:

select * from `users` where `id` = 1

Với Laravel, việc thực hiện điều trên trở nên kín đáo hơn:

// User.php
class User extends Model {
    public $table = 'users';
}

// Query user whose id equals to 1
$id = 1; 
$user = User::find($id);

// Dumping data
var_dump($user); // User object

Rồi, tiếp theo thử dự đoán kết quả cho câu sau:

// Query user whose id equals to something else
$id = '1+23456789';
$user = User::find($id);

// Guess the data ?
var_dump($user); // User object is still here

Điều gì đã xảy ra:

// Case 1
$id = 1;
$user = User::find($id); // => select * from `users` where `id` = '1' limit 1

// Case 2
$id = '1+23456789';
$user = User::find($id); // => select * from `users` where `id` = '1+23456789' limit 1

Như đã thấy, ở cả 2 trường hợp, dữ liệu binding vào câu query đều được Query Builder bao trọn trong dấu nháy đơn ( ' – single quote ). Và khi câu query này được send tới MySQL để thực hiện thì điều duy nhất mong muốn xảy ra ở đây là trường hợp 1 truy vấn được kết quả, trường hợp 2 phải gặp lỗi – do id là field có kiểu int.

Nhưng mà đời không như là mơ. Theo “quy tắc” của MySQL (tham khảo ở đây: https://dev.mysql.com/doc/refman/8.0/en/type-conversion.html), câu lệnh của trường hợp 2 vẫn thực hiện được:

-- This query is .. 
select * from `users` where `id` = '1+23456789' limit 1

-- .. becoming this .. 
select * from `users` where `id` = cast('1+23456789' as int) limit 1

-- .. and finally it turns into this. Bravo! 
select * from `users` where `id` = 1 limit 1

Give thanks to MySQL. You did a great job!

MySQL đã “tự ý” chuyển đổi chuỗi giá trị thành kiểu số, khiến cho câu truy vấn trở nên hợp lệ. Kết quả vẫn được trả về dẫu cho input đầu vào theo mắt thường thì rõ ràng sai rành rành. Việc kết hợp giữa cách binding dữ liệu của công cụ Query Builder nằm trong Laravel cùng với kỹ thuật Type conversion của MySQL đã làm nảy sinh 1 lỗi tiềm ẩn nên được chú ý trong thời gian tới.

bookmark_borderLet’s Encrypt for Custom Domain in Azure’s App Services

1. Đóng gói chứng chỉ SSL đã tạo bởi Let’s Encrypt

Sau khi tạo chứng chỉ SSL sử dụng Let’s Encrypt và muốn dùng để chứng nhận bảo mật lúc tạo Custom Domain cho Azure’s App Service, các file chứng chỉ cần được đóng gói lại bằng câu lệnh sau:

# Go to where Let's Encrypt keeps your certificate 
cd /etc/letsencrypt/live/linhntaim.com 

# Pack the certificate files and create the bundle 
openssl pkcs12 -export \ 
    -out bundle.pfx \ # Bundle file 
    -inkey privkey.pem \ 
    -in cert.pem \ 
    -certfile chain.pem \ 
    -password pass:%password% # Replace %password% with your desired password

2. Cài đặt chứng chỉ cho Custom Domain trong App Service

Sau khi thêm Custom Domain cho App Service, tiến hành cấu hình SSL cho custom domain vừa thêm.

Chọn Upload PFX Certificate:

azure_app_service_custom_domain_ssl_01

Tim và chọn file bundle.pfx (chứng chỉ đã được đóng gói) vừa tạo ở mục 1, đồng thời điền password đã dùng khi tạo file.

azure_app_service_custom_domain_ssl_02

Chọn Upload ở cuối màn hình là xong.

bookmark_borderCài đặt PHP 7.4

PHP vừa mới ra phiên bản 7.4 hôm 28/11/2019. (Xem changelog ở đây).

Nay rảnh nên quyết định cài lên VPS.

1. PHP Package

Trước tiên, để keep-up-to-date với các phiên bản PHP, mình sử dụng PPA của bạn Ondrej (https://launchpad.net/~ondrej/+archive/ubuntu/php):

add-apt-repository ppa:ondrej/php
apt update

Very easy. Lúc này, mình có thể cài đặt bất kỳ phiên bản PHP nào, từ các bản 7.0, 7.2, vv.. cho đến bản 7.4 mới ra lò.

2. Cài đặt PHP 7.4

Sau khi đã đảm bảo việc keep-up-to-date thì tiến hành cài đặt:

apt install php7.4-fpm

Các “thứ” sẽ được cài đặt bao gồm:

php7.4-cli 
php7.4-common 
php7.4-fpm 
php7.4-json 
php7.4-opcache 
php7.4-readline

Các thứ nên/cần được cài thêm:

apt install \ 
php7.4-bcmath \ 
php7.4-bz2 \ 
php7.4-curl \ 
php7.4-gd \ 
php7.4-intl \ 
php7.4-mbstring \ 
php7.4-mysql \ 
php7.4-xml \ 
php7.4-zip

3. Cấu hình PHP 7.4

Thay đổi một số thiết lập trong file php.ini:

# Open file to edit
vi /etc/php/7.4/fpm/php.ini

Vài thiết lập cần/nên được sửa đổi để phù hợp với nhu cầu:

max_execution_time = 300 
max_input_time = 600
memory_limit = 256M 
post_max_size = 100M 
cgi.fix_pathinfo = 0 
upload_max_filesize = 100M

Sau đó, khởi động lại service PHP 7.4 FPM:

service php7.4-fpm restart

4. Cấu hình NGINX chạy PHP 7.4

Tạo file cấu hình chạy PHP cho NGINX:

# Open file to edit
vi /etc/nginx/php.conf

Dưới đây là nội dung file cấu hình tham khảo:

location / { 
    try_files $uri $uri/ /index.php?$query_string; 
} 

location ~ [^/]\.php(/|$) { 
    fastcgi_split_path_info ^(.+?\.php)(/.*)$; 
    if (!-f $document_root$fastcgi_script_name) { 
        return 404; 
    } 
    fastcgi_pass unix:/run/php/php7.4-fpm.sock;
    fastcgi_index index.php; 
    fastcgi_param HTTP_PROXY ""; 
    include fastcgi.conf; 
}

File này có thể được tái sử dụng nhiều lần khi thiết lập các website chạy trên NGINX. Ví dụ về thiết lập cho subdomain dev.linhntaim.com sử dụng mã nguồn WordPress có sử dụng thông tin cấu hình từ php.conf:

server { 
    listen 443 ssl http2; 
    listen [::]:443 ssl http2; 

    server_name dev.linhntaim.com; 

    include ssl.conf; 
    
    index index.php index.html; 
    
    ... 

    include php.conf; # PHP configuration
}

Sau khi đã tạo/chỉnh sửa các file cấu hình, thực hiện kiểm tra và khởi động lại service NGINX:

nginx -t 
service nginx restart

Hoàn tất.

5. Vài điều cần lưu ý sau khi cài đặt PHP 7.4

PHP 7.4 đã hỗ trợ và mặc định khi kết nối với CSDL MySQL 8.0 sẽ sử dụng tài khoản có password được mã hóa theo caching_sha2_password. Do vậy, khi tạo tài khoản trên CSDL MySQL 8.0 để kết nối từ mã nguồn PHP 7.4, cần tạo với câu lệnh sau:

-- A very clearly way to create an account with password hashed by caching_sha2_password
create user 'php7.4'@'localhost' identified with caching_sha2_password by 'password'; 

-- Or because MySQL 8.0 has caching_sha2_password as default method, we simply excute this 
create user 'php7.4'@'localhost' identified by 'password';

Đối với những tài khoản đã tạo với password được mã hóa theo mysql_native_password hoặc phương thức khác, để cập nhật password với phương thức mới, dùng câu lệnh sau:

alter user 'php7.4'@'localhost' identified with caching_sha2_password by 'password';

Khi cảm thấy ổn với phiên bản PHP 7.4 sau một thời gian sử dụng, tiến hành xóa bỏ các phiên bản cũ hơn nếu không cần dùng nữa:

apt remove \ 
php7.3-fpm \ 
php7.3-common \ 
php7.3-bcmath \ 
php7.3-bz2 \ 
php7.3-curl \ 
php7.3-gd \ 
php7.3-intl \ 
php7.3-mbstring \ 
php7.3-mysql \ 
php7.3-xml \ 
php7.3-zip 

apt autoremove --purge 

rm -r /etc/php/7.3

bookmark_borderLàm gì với cái server mới

1. Quyết định thầu một cái VPS

Hết tháng 11 là hết hạn dùng cái AWS free đăng ký từ 1 năm trước. Cũng định sẽ purchase để xài tiếp cơ mà khá đắt, nên lại thôi; dù trên đó có quá đầy đủ các dịch vụ mình cần. Quẩn quanh mấy nhà cung cấp dịch vụ Cloud ở Việt Nam mà phí còn đắt hơn.

Thế là chuyển sang ý định sẽ mua một gói VPS rẻ rẻ nào đấy. Cuối cùng thì quay về với PA Vietnam – nơi mình cũng đang cắm tên miền cá nhân mấy năm nay. Nói chung là rẻ nhất so với cấu hình/dịch vụ ở các chỗ khác.

Đăng ký xài luôn một năm, bắt đầu từ 16/11/2019. Ban đầu nói chung thấy ổn. Chưa có gì phải phàn nàn. May đăng ký sớm, vừa được mấy hôm thì thằng AWS gửi mail báo không charge được thẻ visa lần thứ n (lười đi làm lại thẻ visa vãi xoài) và nó chuẩn bị cho suspend tài khoản. Nó còn nhắc khéo rằng ‘mày liệu mà backup dữ liệu’; hú hồn con chồn là mình đã backup hết từ lâu rồi.

2. VPS để làm gì

Khi nhu cầu tăng cao, nếu chỉ có cái hosting thì không thể đáp ứng được. Công nghệ web đang tiến triển quá nhanh. PHP? HTML? MySQL? Các hệ thống web bây giờ kiểu như trăm hoa đua nở, mà nếu để bắt kịp trending thì chẳng có cách nào khác ngoài việc tìm hiểu và ứng dụng cái đống ‘trăm hoa’ đấy.

Vậy là nhu cầu, hiện, không chỉ dừng lại ở việc chăm chút, xây dựng mấy cái site cá nhân con con nữa; mà còn là thử nghiệm các công nghệ mới, demo các dự án tự phát triển – trước hết là thế, còn đâu thì vân vân và mây mây.

3. Dự án VPS

Với cái server mới, đầu tiên, mình đang dùng để tạo mạng lưới các trang thông tin cá nhân. Các bài viết có xu hướng lãng mạn văn học đã được chuyển từ domain chính sang subdomain hey.linhntaim.com. Domain chính linhntaim.com sẽ trở thành kiểu như 1 cái portal chứa thông tin để chuyển vào các subdomain khác. Subdomain dev.linhntaim.com này được dùng để ghi lại các vấn đề liên quan đến công việc chuyên môn hiện tại cũng như các thứ kỹ thuật/kinh nghiệm thu lượm được khi thực hiện dự án VPS – dự án sử dụng và duy trì sử dụng VPS nhiều năm về sau – này. Resume.linhntaim.com vẫn là nơi chứa thông tin Resume/CV của mình, tuy nhiên mình đang muốn rework lại trang này trên nền Vue.js thay vì sự kết hợp nửa vời giữa PHP vs. HTML như hiện tại. Pinkspirit.linhntaim.com chưa làm được – need more time. Dự định sẽ làm 1 trang photos.linhntaim.com để share ảnh.

Tiếp theo, một số sản phẩm cần có nơi để trưng bày. Slack-apps.linhntaim.com đã available – nhưng chắc cần làm cái homepage giới thiệu các apps mình làm cho Slack. Katniss.linhntaim.com cần upgrade và test trên Laravel bản mới. Chichi.linhntaim.com cần work thêm để cập nhật core. Cần tính xem nên làm cái cheeeh.linhntaim.com đến đâu, nhất là phần storage để cập nhật ngược lại project Chichi.

Song song với đó, việc thiết lập, cài cắm hệ thống của cái VPS cũng sẽ cần được lưu ý và triển khai. Mới chạy được 2 tuần, còn cần cải tạo, cải thiện nhiều thì mới chuẩn chỉ được.

4. Còn nữa

Như vậy là mỗi năm, ngoài phí duy trì domain, mình sẽ phải thêm phí duy trì cho vụ VPS này. Nó có quan trọng không khi phải keeping mấy khoản chi phí đó. Mình nghĩ là có. Đã từng có lúc mình cho rằng con người ta phải tự đi từ con số 0 tới con chữ Z – sẽ tốt hơn khi người ta thử nghiệm mọi thứ đúng-sai mà không có bất kỳ tác động khách quan nào – thì họ mới có đủ tỉnh táo để suy xét hết góc cạnh của từng vấn đề họ gặp phải trên bước đường phát triển được. Nhưng rồi mình bắt đầu có thêm cách tiếp cận khác trong suy nghĩ: những thứ này không phải để tác động lên bất kỳ ai, không phải áp đặt lối mòn tư duy lên bất kỳ bộ óc nào; ở đây, đơn giản chỉ là những kinh nghiệm được lưu trữ. Việc tạo ra những thông tin này là hoàn toàn thiết thực, cả cho phía mình nói riêng lẫn cho phía cộng đồng nói chung. Nó đáng ra là việc nên để tâm làm từ lâu rồi mới phải.

Vậy thì, hi vọng dự án VPS sẽ kéo dài càng lâu càng tốt. Và những thông tin mà nó lưu trữ được sẽ giúp ích cho mọi người. Di sản không ở đâu xa. Di sản là những gì quanh ta. Đối chọi với buổi chiều tà. Vầng dương lặn rồi nhưng chưa tắt. Rọi bóng chim muông trước cửa nhà.