SourceHut 被 DDoS 後的報告

SourceHut 在 DDoS 後發表了報告:「SourceHut network outage post-mortem」。

這次的攻擊在 L3 層,直接塞爆 upstream bandwidth:

At around 06:00 UTC on January 10th, a layer 3 distributed denial-of-service (DDoS) attack began to target SourceHut’s PHL infrastructure.

上游 Cogent 選擇 null route 掉:

In response to the attack, Cogent announced null routes for our downstream AS, causing our PHL network to become unreachable both for SourceHut staff and the general public.

中間有試著問 Cloudflare 以及其他的方案,但依照他們的說法,費用上無法承受:

We initially researched a number of solutions, and spoke to Cloudflare in particular due to their ability to provide a rapid response to ongoing incidents. However, given our complex requirements, Cloudflare quoted us a figure which was not attainable within our financial means as a small company. Other options we researched (though we did not seek additional quotes) had similar economical constraints.

後來的解法是在 OVH 放 proxy server (搭配 OVH 的 DDoS 保護服務),然後導到沒有公開的 subnet:

However, we found that OVH’s anti-DDoS protections were likely suitable: they are effective, and their cost is amortized across all OVH users, and therefore of marginal cost to us. To this end the network solution we deployed involved setting up an OVH box to NAT traffic through OVH’s DDoS-resistant network and direct it to our (secret) production subnet in AMS; this met our needs for end-to-end encryption as well as service over arbitrary TCP protocols.

GitHub 在還沒被 Microsoft 併購前 (2018 年) 也有被打的記錄,2015 年的時候 Google 有放一些資料,當年有寫一篇記錄下來:「Google 對 GitHub 先前遭受 GFW 的 DDoS 攻擊的分析」,不過當年這波是 L7 的。

另外 2016 年的時候 GitHub 也有整理一篇關於 TCP SYN flood 的阻擋方式,這個看起來比較接近這次的攻擊:「GitHub 對抗 TCP SYN Flood 的方式:synsanity」。

PostgreSQL 15 將可以對透過 UNIQUE 限制 NULL 的唯一性了

看到「Waiting for PostgreSQL 15 – Add UNIQUE null treatment option」這篇文章裡面提到 PostgreSQLUNIQUE 多加了一些功能進去:「Add UNIQUE null treatment option」。

The SQL standard has been ambiguous about whether null values in unique constraints should be considered equal or not.  Different implementations have different behaviors.  In the SQL:202x draft, this has been formalized by making this implementation-defined and adding an option on unique constraint definitions UNIQUE [ NULLS [NOT] DISTINCT ] to choose a behavior explicitly.

This patch adds this option to PostgreSQL.  The default behavior remains UNIQUE NULLS DISTINCT.  Making this happen in the btree code is pretty easy; most of the patch is just to carry the flag around to all the places that need it.

The CREATE UNIQUE INDEX syntax extension is not from the standard, it's my own invention.

I named all the internal flags, catalog columns, etc. in the negative ("nulls not distinct") so that the default PostgreSQL behavior is the default if the flag is false.

Reviewed-by: Maxim Orlov 
Reviewed-by: Pavel Borisov 
Discussion: https://www.postgresql.org/message-id/flat/84e5ee1b-387e-9a54-c326-9082674bde78@enterprisedb.com

以往針對某個欄位下 UNIQUE 後,雖然同樣的值是無法 INSERT 進去,但 NULL 則是個例外,是可以塞多次進去的。

現在則是提供選項指定對 NULL 的解讀了;預設還是保留原來行為的 UNIQUE NULLS DISTINCT (把每個 NULL 都當作不同的值看待),特別指定後會變成 UNIQUE NULLS NOT DISTINCT (把每個 NULL 都當作一樣的值,進而被 UNIQUE 條件限制)。

在下一個版本的 PostgreSQL 15 就會出現這個功能了...

YAML 的問題 (挪威問題)

Hacker News 首頁上看到的,YAML 寫多的人都遇過類似的問題:「The Norway Problem - why StrictYAML refuses to do implicit typing and so should you」,對應的討論「The Norway Problem (hitchdev.com)」也可以看一下。

第一個「經典」是字串不需要包起來就很容易出事,這邊提到的例子是因為保留字而中槍,挪威的簡碼 NO 變成 False 了:

countries:
- GB
- IE
- FR
- DE
- NO
>>> from pyyaml import load
>>> load(the_configuration)
{'countries': ['GB', 'IE', 'FR', 'DE', False]}

同樣的是字串問題,「看起來」是數字的就會變成數字:

python: 3.5.3
postgres: 9.3

然後還是字串,人名遇到保留字:

first name: Christopher
surname: Null

這種問題都是碰過一次學一次...

作者另外提到的 StrictYAML 改變了 YAML 規格,我會看看就好,能用 JSON 也許還是會偏好先用 JSON,不是完全解決,但踩雷的機率會少很多。

Amazon Aurora 改善 ALTER TABLE 時增加 column 的速度

Amazon Aurora (MySQL) 提昇了增加 column 操作的速度:「Amazon Aurora Supports Fast DDL Operations」,細節可以在「Amazon Aurora Under the Hood: Fast DDL」這邊看到。

這次加速是限制在 nullable 欄位:

We’re addressing this mess, starting with the most common DDL operation we’ve seen: adding a nullable column at the end of a table.

MySQL 5.6 (Online DDL Overview) 與 5.7 (Online DDL Overview) 都有列出增加 column 需要 rebuild table。

對於一般的 MySQL server 來說,增加 column 這種事情通常都會用 pt-online-schema-change 解決,Amazon Aurora 這個改善算是讓 DBA 可以輕鬆一些...

Jennifer Null 的故事...

在「These unlucky people have names that break computers」這邊看到了這個故事,Jennifer Null 因為 "Null" 而導致在很多電腦系統上出錯,這讓我想到這個經典的 xkcd 笑話:

滿滿的 SQL injection 的味道 XDDD

Facebook 推出靜態分析工具:Facebook Infer

Facebook 推出了靜態分析工具 Facebook Infer,可以事先找出 AndroidiOS 上的 bug:Open-sourcing Facebook Infer: Identify bugs before you ship

從官方給的操作動畫中就可以看出來怎麼跑了。目前看起來支援三種程式語言,C、Objective-C、Java:

Facebook Infer is a static analysis tool - if you give Infer some Objective-C, Java, or C code, it produces a list of potential bugs.

在 Android 上 (Java) 會找出的類型:

Infer reports null pointer exceptions and resource leaks in Android and Java code.

iOS 上則只找 memory leak:

In addition to this, it reports memory leak problems in iOS and C code.

比較特別的是,這個工具是用 OCaml 寫:

Infer is a static analysis tool for Java, Objective-C and C, written in OCaml.

MySQL 裡儲存時間的方式...

這應該是 MySQL 的 best practice 之一,不知道為什麼 Baron Schwartz 又拿出來講:「A simple rule for sane timestamps in MySQL」。

MySQL 內可以儲存「日期與時間」的資料型態是 DATETIME 與 TIMESTAMP 兩種,不過 DATETIME 沒有時區觀念,而 TIMESTAMP 只能是 UTC (GMT+0)。

相較於隔壁棚 PostgreSQLDate/Time Types 就一種 TIMESTAMP,但支援 with timezone 與 without timezone 直接解決問題。

這使得 MySQL 上在儲存「日期與時間」以及處理的時候一直有種 WTF 的感覺...

就如同 Baron Schwartz 的建議,如果使用 MySQL,目前比較好的方法是用 INT UNSIGNED NOT NULL 儲存,把 timezone 的處理都放到應用程式端來處理,這樣產生的問題會比較少...

真的需要在 INSERT 或是 UPDATE 時更新欄位,可以用 trigger 處理,彈性反而比內建功能大不少。

關於 Non-null string 的處理...

上一篇「Filter Input & Escape Output...」有提到 Non-null UTF-8 string 的 filter,結果剛剛洗澡的時候想了想,好像寫錯了?

問題在於「到底是先 de-null 再 iconv(),還是先 iconv() 再 de-null」的問題。

這個問題其實跟 iconv() 成 UTF-8 時遇到不合法字元時怎麼實做有關,也就是 undefined behavior... 由於 \0 是合法的 UTF-8 character,所以我們假設某一種實做是當 iconv() 遇到不合法字元時會用 \0 帶進去:

先 de-null 再 iconv()

這是上一篇文章提到的方法。但在上面提到的 iconv() 實做下卻是有問題的方法。原因很簡單,de-null 後沒有 \0 的字串,卻會因為 iconv() 而產生 \0

先 iconv() 再 de-null

這邊要考慮的是最後 de-null 後會不會變成 invalid UTF-8 string。答案是不可能,因為 iconv() 轉出來後保證是 UTF-8 string (不論如何處理非 UTF-8 character 的部份),而 UTF-8 string 內的 \0 一定可以當 separator,所以切下去一定還是 UTF-8 string。(可以參考下圖關於 UTF-8 character 的規則)

所以?

可能以現在的 iconv() 實做來說,兩者都不會有問題,但寫程式的時候總是要避免 side-effect,所以後者的方法會比前者好。