8

如何安全地为 Homebrew 替换中国大陆镜像源

 3 years ago
source link: https://phuker.github.io/homebrew-china-mirror.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

关于 Homebrew 在国内换源的文章一搜一大把,洒家并不想复制镜像的帮助页面再制造一篇,而是想讨论一下如何在不降低安全性的情况下使用镜像源。

注:“不降低”指的是换源后,安全性和不换源相同。原始源仓库被上传恶意代码、SHA-256 hash 碰撞攻击等场景则不在本文讨论范围之内。

概述

“Homebrew”的意思是家酿啤酒。毕竟是家酿的,Homebrew 还是比不上 APT 这种正规的包管理器,很多设计相当凑合。它有以下特点:

  • Homebrew 本身和它的各个索引仓库(tap)是通过 Git 管理的
  • 没有 GPG 签名,完整性检验靠的是索引的 SHA-256,因此索引是一个关键点
  • 没有配置文件,配置全靠 git config 和环境变量

一般换源都是同时替换索引镜像二进制预编译包镜像。洒家作为受迫害妄想症搞信息安全的,马上就想到这里面显然有供应链攻击的可能性。如果镜像被黑客劫持,或者镜像自身作恶,那么用户的电脑就白给了。

  • 也有受迫害妄想症重视安全
  • 有一个较快的梯子,但是还是不如镜像快

那么可以使用下面的方法换源。

换源

总体来看,一共有 3 类资源需要分别处理:

  • 包含 SHA-256 hash 的原始索引仓库:通过代理访问
  • 二进制预编译文件:使用镜像下载
  • 有些二进制预编译文件镜像里没有:还是需要一个 fallback 代理

Git 设置代理

首先使用原版方式安装 Homebrew,不要替换 Git 仓库的 origin。此时 Git 仓库的 origin 是 GitHub,需要给它们加上代理。以下两种方式任选一种即可。

全局设置

一般我们可以全局设置 Git 使用 HTTP/HTTPS 协议访问 GitHub 时使用代理。假设代理服务器地址为 socks5h://127.0.0.1:1080,运行下面的命令即可。

git config --global http.https://github.com.proxy socks5h://127.0.0.1:1080

逐个仓库设置

如果你不想修改全局设置,也可以逐个仓库设置代理。

列出所有需要处理的 Git 仓库:

brew --repo
for repo in $(brew tap)
do
    brew --repo "${repo}"
done

假设代理服务器地址为 socks5h://127.0.0.1:1080,逐个 cd 进去,运行:

git config --local http.proxy socks5h://127.0.0.1:1080

注:运行 man git-config 查阅文档,并动手实验验证,可以证实不存在 https.proxy 配置项,只需配置 http.proxy 即可同时控制 HTTP 和 HTTPS 协议的代理,网络流传的一些方法是错误的。

配置 Homebrew

上文提到,Homebrew 没有配置文件,我们要用到的各种配置全都需要通过环境变量设置。假设代理服务器地址为 socks5h://127.0.0.1:1080,把下面的 alias 添加到你的 shell 配置中即可。

alias brew='HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK=1 HOMEBREW_BOTTLE_DOMAIN=https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles HOMEBREW_CLEANUP_MAX_AGE_DAYS=30 no_proxy=".cn" http_proxy="socks5h://127.0.0.1:1080" https_proxy="${http_proxy}" ALL_PROXY="${http_proxy}" /usr/local/bin/brew'

其中设置了一些个人认为有用的参数:

  • HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK:禁止 bottle 下载失败时 fallback 到源码编译。个人认为程序干得太多也会过犹不及。假设暂时的网络波动导致 bottle 下载失败,从源码编译又要下载一大堆编译依赖,然后又会下载失败,这只会把事情搞得更糟。
  • HOMEBREW_BOTTLE_DOMAIN:设置二进制预编译包的镜像,此处设置为清华大学开源软件镜像站。
  • HOMEBREW_CLEANUP_MAX_AGE_DAYS:删除超过此天数的缓存文件,默认是 120 天。

PoC

下面来证明控制了索引和 bottle 源镜像就控制了一切。

环境版本信息:

  • Homebrew:2.5.11-22-g66b6828
  • macOS:Catalina 10.15.7-x86_64

模拟索引仓库被控制的场景,创建一个 formula 文件 /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/formula/phuker-test.rb,内容为:

class PhukerTest < Formula
  desc "PoC"
  homepage "https://www.example.com/"
  url "http://127.0.0.1:8181/phuker-test-1.0.0.tar.gz"
  sha256 "0000000000000000000000000000000000000000000000000000000000000000"

  bottle do
    rebuild 1
    sha256 "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" => :catalina
  end

  def install
    system "make", "install"
  end
end

创建一个简单的 .tar.gz bottle 文件,此文件的 SHA-256 hash 需要填到 .rb formula 文件的对应位置。文件结构为:

$ cd /tmp/brew/homebrew-bottles/bottles/
$ tar -tvf phuker-test-1.0.0.catalina.bottle.1.tar.gz
drwxr-xr-x  0 phuker   wheel       0 11 18 09:59 phuker-test/
drwxr-xr-x  0 phuker   wheel       0 11 18 09:59 phuker-test/1.0.0/
drwxr-xr-x  0 phuker   wheel       0 11 18 09:59 phuker-test/1.0.0/bin/
-rwxr-xr-x  0 phuker   wheel      23 11 18 09:59 phuker-test/1.0.0/bin/phuker-test

.tar.gz bottle 文件中的 phuker-test/1.0.0/bin/phuker-test 可执行文件内容为:

#!/bin/sh

echo 'Pwn!'

启动 Web 服务,模拟 bottle 镜像源:

$ cd /tmp/brew
$ python3 -m http.server --bind 0.0.0.0 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
127.0.0.1 - - [18/Nov/2020 10:00:04] "GET /homebrew-bottles/bottles/phuker-test-1.0.0.catalina.bottle.1.tar.gz HTTP/1.1" 200 -

安装并执行命令:

$ export HOMEBREW_NO_AUTO_UPDATE=1
$ export HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK=1
$ export HOMEBREW_BOTTLE_DOMAIN=http://127.0.0.1/homebrew-bottles
$ /usr/local/bin/brew install phuker-test
==> Downloading http://127.0.0.1/homebrew-bottles/bottles/phuker-test-1.0.0.catalina.bottle.1.tar.gz
======================================================================== 100.0%
==> Pouring phuker-test-1.0.0.catalina.bottle.1.tar.gz
🍺  /usr/local/Cellar/phuker-test/1.0.0: 2 files, 878B
$ phuker-test
Pwn!

Q.E.D.

扩展阅读


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK