代码之家  ›  专栏  ›  技术社区  ›  jasonharper

无互联网连接的WiFi连接设备的最佳实践

  •  8
  • jasonharper  · 技术社区  · 7 年前

    我所在的公司生产一种设备,通过WiFi提供基于Web的设置和操作界面。该设备通常会在偏僻的地方使用,因此无法假设现有WiFi网络的存在:因此,该设备的WiFi模块作为接入点运行,并通过HTTP提供奇特的HTML5 web应用程序(这是我在2013年选择的WiFi模块唯一可用的选项,当时该模块最初是实现的)。

    这起作用了 太棒了 起初,但随着网络的发展,它正在慢慢瓦解。特别是两个问题:

    • web应用程序的一部分涉及映射,当然,能够在地图上显示“you are here”标记非常有用,但Chrome已经拒绝通过HTTP支持HTML5地理定位API(甚至没有明确信任页面的选项),而且看起来所有其他浏览器都会效仿。

    • 这个web应用程序非常大(WiFi模块非常慢),所以我使用HTML5应用程序缓存功能在初次使用该应用程序后有效地获得即时页面加载。不幸的是,主要的浏览器已经拒绝在HTTP上使用此功能,该功能已经被弃用,并且它的后续功能(服务工作者)明确地只有HTTPS。

    我不得不重做此功能的硬件和软件,因为原来的WiFi模块不再可用。现在可用的模块有更多的CPU能力和存储空间(成本是原来的十分之一),因此现在可以做很多事情,比如通过HTTPS为web应用提供服务。我对这种设备的普遍建议是 获取正确的SSL证书 ,但我不认为这在我的情况下会起什么作用:

    • 当设备实际使用时,通常不会有可用的Internet连接,因此无法验证证书。

    • 通过其IP地址访问设备 192.168.1.1 ,或通过LLMNR/mDNS名称 ui.local 。任何一种地址都不提供SSL证书。

    • 我需要这个来工作 永远 -设备中没有更新证书的机制。即使是10年(许多自签名证书生成器提供的最长有效期)也不够;我拒绝在设备中加入计划的淘汰。

    也许可以通过在设备上添加DNS服务器来实现这一点,基本上使其成为一个固定门户,这样就可以通过一个正常的URL访问它,而我实际上可以为其购买SSL证书。然而,我看到了这方面的许多潜在问题:

    • 如果用户的计算设备设置了静态DNS服务器地址(8.8.8.8或其他),而不是从DHCP接受DNS服务器地址,则会失败。

    • 如果用户实际上与设备的WiFi连接同时具有Internet连接,则会失败。

    • 它失败了 永久地 如果DNSSEC流行起来。

    • 还有证书过期的问题。

    尽管所有建议都与此相反,但这似乎使自签名证书成为唯一可行的选择。一个常见的反对意见是“你在教用户忽略有效的安全警告”;我明白你的意思,但我该怎么办呢?

    有没有什么方法是我忽视的,可以让我的设备继续像2013年那样与现代浏览器配合使用?

    2 回复  |  直到 7 年前
        1
  •  3
  •   Robert    7 年前

    我同意你的观点,通过HTTPS访问局域网中没有公共地址的设备是一个棘手的问题。

    IMHO应该有一个特殊的TLS版本来寻址这些设备,但是目前还没有这样的标准。

    在我看来,只有自签名证书似乎是可行的。然而,当您谈到“自签名证书生成器”时,我感到很冷,因为您应该 切勿为设备配备预生成的自签名证书 哦! 从安全角度来看,这是你能做的最糟糕的事情之一,因为预生成的证书和密钥对总是可以从固件中提取出来,然后用来攻击你的一个客户(联想和其他计算机制造商刚刚了解到,在过去几年中 hard way )哦! 对于自签名证书,只有一种方法:

    1. 当设备首次启动时,等待处理足够的数据(播种),以便随机生成器可以生成安全的随机数据。

    2. 使用生成的随机数据生成公钥/私钥对

    3. 使用先前生成的密钥对生成自签名证书。使用正确的命令,您可以将有效期结束设置为您想要的任何日期。

    请注意,您可以随时重新执行步骤3,例如,当用户重新配置IP地址时,您必须在证书中更新该地址。对于自主开发的客户端(例如,在Android或iOS上),您可以执行公钥固定,这意味着无需(重新)安装证书。

    不幸的是,对于web浏览器来说,即使使用相同的公钥,新证书也意味着您必须以受信任的身份重新安装证书。

    关于HTML5地理定位API:您不能通过HTTPS使用此API吗?只有当您在HTTPS页面中使用HTTP资源时,混合内容才是一个问题,但反过来也不会有问题。

    顺便说一句:我发现了一些你可能感兴趣的幻灯片,即使在这种情况下,你可以上网。也许你会从中得到一些新的想法: https://www.w3.org/wiki/images/6/6c/TPAC2016_Local_Discovery_and_HTTPS.pdf

        2
  •  0
  •   helvete user3408541    7 年前

    您可以指定所需的自签名证书的任何过期时间。它是openssl的一个参数(-days)。

    以下证书将在100年后到期:

    openssl x509 -in localhost.pem -text -noout
    
    Certificate:
        Data:
            Version: 3 (0x2)
            Serial Number:
                c2:a8:fc:a1:29:02:96:dd
        Signature Algorithm: sha256WithRSAEncryption
            Issuer: C = US, ST = New York, L = New York, O = localhost, OU = Testing Domain, CN = localhost
            Validity
                Not Before: Apr  7 02:25:51 2018 GMT
                Not After : Mar 14 02:25:51 2118 GMT
            Subject: C = US, ST = New York, L = New York, O = localhost, OU = Testing Domain, CN = localhost
            Subject Public Key Info:
                Public Key Algorithm: rsaEncryption
                    Public-Key: (2048 bit)
                    Modulus:
                        00:96:89:c9:b4:8f:c0:2e:4c:92:15:cd:df:23:b2:
                        f1:6f:34:95:ca:e2:a4:c2:95:3f:1f:b3:50:56:16:
                        65:5a:1a:b9:99:6b:19:67:f0:13:54:76:23:4c:cd:
                        f5:2a:25:6c:d2:e0:67:e9:d5:34:0e:8f:2d:2b:dc:
                        04:3f:bb:e4:07:bd:a4:7a:ee:58:87:6b:cc:b7:1e:
                        79:fc:fc:bd:81:c7:e0:24:1d:91:14:50:70:5b:60:
                        13:ad:c7:eb:fb:67:3b:a9:e5:83:33:fb:ef:f4:26:
                        00:12:e3:af:e9:1e:e9:a2:5b:d1:98:3c:13:c0:30:
                        f0:13:9c:52:a3:b1:e7:3a:73:47:ce:ab:f9:5f:c4:
                        ff:74:1e:0c:86:ec:83:d6:b5:6d:36:31:00:26:97:
                        d8:74:39:cb:75:24:31:39:cc:e4:a1:78:38:92:07:
                        b4:a5:06:5a:8e:8b:0c:fa:7e:5e:55:7e:59:cf:f1:
                        1f:05:2e:e6:c2:6a:cf:4c:03:6a:66:b8:19:64:ae:
                        90:81:d9:28:37:2f:09:c1:b3:98:8a:bf:39:0a:0b:
                        23:db:55:79:02:83:fe:9d:be:ac:b8:3c:e5:1e:76:
                        5c:69:fe:f4:34:78:d4:36:82:0f:6e:c1:19:fe:39:
                        7f:fd:f0:4f:13:b6:2a:26:e6:ce:b0:fd:51:3d:38:
                        61:41
                    Exponent: 65537 (0x10001)
            X509v3 extensions:
                X509v3 Subject Key Identifier: 
                    D6:DF:EB:FA:73:85:C9:22:AA:6D:79:E5:F9:16:01:2B:CC:E7:D8:D0
                X509v3 Authority Key Identifier: 
                    keyid:D6:DF:EB:FA:73:85:C9:22:AA:6D:79:E5:F9:16:01:2B:CC:E7:D8:D0
    
                X509v3 Basic Constraints: critical
                    CA:TRUE
        Signature Algorithm: sha256WithRSAEncryption
             4f:ca:30:3f:fe:61:73:16:3f:a1:6d:5a:35:c1:b6:97:d6:63:
             89:34:6e:05:e6:e6:84:7b:3b:b4:fc:89:65:7a:31:46:97:8f:
             00:11:c7:61:97:86:b8:31:c7:a7:91:f7:c9:19:4e:0a:39:d7:
             5e:95:52:17:92:8a:84:ce:6a:1b:1c:14:f2:15:18:62:78:07:
             1e:d9:3c:5d:9c:28:65:42:bf:4f:61:0f:a3:86:e6:ff:38:34:
             23:97:11:20:3c:5b:82:4a:ea:05:af:6d:5e:83:30:be:6d:64:
             de:85:b8:bb:89:60:59:7a:c8:1f:ba:2d:02:04:34:89:65:32:
             2c:10:f7:db:97:c3:ba:e2:ed:27:8a:bb:8d:9e:92:0a:d3:2e:
             ad:9e:fb:15:fc:25:73:0d:e2:f9:45:3b:18:fd:89:e6:6b:31:
             18:64:46:e2:dc:ad:e0:f3:f8:c1:b2:e6:93:bc:b3:db:9a:bc:
             d3:58:38:68:e2:28:b4:6d:ca:07:d8:af:21:dc:10:bd:c0:75:
             3f:b1:d2:24:96:5d:dd:a3:d2:e2:95:39:67:6b:06:bb:4d:91:
             76:4f:9b:ce:7f:25:39:47:73:3e:fd:81:82:15:ac:6a:2c:cb:
             82:76:04:b1:91:41:cf:8a:68:70:cd:7d:3f:2f:c9:1d:d5:a7:
             3e:d0:3d:00
    

    您可以使用以下脚本生成它:

    #! /bin/bash
    
    mkdir /tmp/scert 2>/dev/null
    rm -r /tmp/scert/* 2>/dev/null
    
    if [ $# -ne 1 ];
    then
        echo "Usage: scert <name>"
        exit
    fi
    
    if [ -e "/etc/ssl/private/$1.key" ];
    then
        echo "/etc/ssl/private/$1.key already exists"
        exit
    fi
    
    if [ -e "/etc/ssl/certs/$1.crt" ];
    then
        echo "/etc/ssl/certs/$1.crt already exists"
        exit
    fi
    
    if [ -e "/etc/ssl/certs/$1.pem" ];
    then
        echo "/etc/ssl/certs/$1.pem already exists"
        exit
    fi
    
    echo "[req]" > /tmp/scert/tmp.cnf
    echo "default_bits = 2048" >> /tmp/scert/tmp.cnf
    echo "prompt = no" >> /tmp/scert/tmp.cnf
    echo "default_md = sha256" >> /tmp/scert/tmp.cnf
    echo "distinguished_name = dn" >> /tmp/scert/tmp.cnf
    echo "" >> /tmp/scert/tmp.cnf
    echo "[dn]" >> /tmp/scert/tmp.cnf
    echo "C=US" >> /tmp/scert/tmp.cnf
    echo "ST=New York" >> /tmp/scert/tmp.cnf
    echo "L=Rochester" >> /tmp/scert/tmp.cnf
    echo "O=$1" >> /tmp/scert/tmp.cnf
    echo "OU=Testing Domain" >> /tmp/scert/tmp.cnf
    echo "emailAddress=spam@uce.gov" >> /tmp/scert/tmp.cnf
    echo "CN = localhost" >> /tmp/scert/tmp.cnf
    
    echo "authorityKeyIdentifier=keyid,issuer" > /tmp/scert/tmp.ext
    echo "basicConstraints=CA:FALSE" >> /tmp/scert/tmp.ext
    echo "keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment" >> /tmp/scert/tmp.ext
    echo "subjectAltName = @alt_names" >> /tmp/scert/tmp.ext
    echo "" >> /tmp/scert/tmp.ext
    echo "[alt_names]" >> /tmp/scert/tmp.ext
    echo "DNS.1 = localhost" >> /tmp/scert/tmp.ext
    
    openssl genrsa -des3 -passout pass:xxxx -out /tmp/scert/tmp.pass.key 2048
    openssl rsa -passin pass:xxxx -in "/tmp/scert/tmp.pass.key" -out "/tmp/scert/tmp.key"
    
    openssl req -x509 -new -nodes -key /tmp/scert/tmp.key  -subj "/C=US/ST=New York/L=New York/O=$1/OU=Testing Domain/CN=localhost" -sha256 -days 36500 -out /tmp/scert/$1.pem
    
    openssl req -new -sha256 -nodes -out /tmp/scert/tmp.csr -newkey rsa:2048 -keyout /tmp/scert/$1.key -config <( cat /tmp/scert/tmp.cnf )
    
    openssl x509 -req -in /tmp/scert/tmp.csr -CA /tmp/scert/$1.pem -CAkey /tmp/scert/tmp.key -CAcreateserial -out /tmp/scert/$1.crt -days 36500 -sha256 -extfile /tmp/scert/tmp.ext
    
    if [ -e "/tmp/scert/$1.key" ];
    then
        sudo cp /tmp/scert/$1.key /etc/ssl/private
        sudo chown root:ssl-cert /etc/ssl/private/$1.key
        sudo chmod 640 /etc/ssl/private/$1.key
        ls -al /etc/ssl/private/$1.key
    else
        echo "ERROR: /tmp/scert/$1.key not found"
    fi
    
    if [ -e "/tmp/scert/$1.crt" ];
    then
        sudo cp /tmp/scert/$1.crt /etc/ssl/certs
        sudo chown root:root /etc/ssl/certs/$1.crt
        sudo chmod 755 /etc/ssl/certs/$1.crt
        ls -al /etc/ssl/certs/$1.crt
    else
        echo "ERROR: /tmp/scert/$1.crt not found"
    fi
    
    if [ -e "/tmp/scert/$1.pem" ];
    then
        sudo cp /tmp/scert/$1.pem /etc/ssl/certs
        sudo chown root:root /etc/ssl/certs/$1.pem
        sudo chmod 755 /etc/ssl/certs/$1.pem
        ls -al /etc/ssl/certs/$1.pem
    else
        echo "ERROR: /tmp/scert/$1.pem not found"
    fi
    
    rm -r /tmp/scert/* 2>/dev/null
    
    echo "DONE"