OpenSSH authorized_keys文件的最佳perl正则表达式?

时间:2018-01-16 22:05:35

标签: regex perl ssh pcre openssh

我在perl中编写了一个小程序,用于解析包含由OpenSSH的ssh-keygen创建的公钥的授权文件。

  • 文件中的每个有效行都包含一个公钥。
  • 将跳过以“#”开头的空行和行。
  • 线条可以非常长,最高可达8kB。

公钥由以下空格分隔的字段组成,依次为:

  • options [可选]任意数量的逗号分隔的不区分大小写的选项规范。除了双引号外,不允许使用空格..
  • keytype [required] keytype是一个字母数字字符串,可以包含短划线或下划线。
  • base64-encoded key [必需]一个不包含空格的字符串
  • 评论[可选]一个可能包含空格的字符串

注意,我在实际程序中验证正则表达式之外的keytype和base64编码键,以便在将来从OpenSSH中添加或删除关键算法时更容易进行维护。正则表达式只是解析行。

2 个答案:

答案 0 :(得分:2)

OpenSSH的docs

  

authorized_keys的格式在sshd(8)手册页中有描述。

sshd(8) manual page

  

AuthorizedKeysFile指定包含公钥[...]每个的文件   该文件的行包含一个键(空行和以。开头的行)   一个'#'被忽略为评论)。 公钥包含以下内容   以空格分隔的字段:options,keytype,base64-encoded key,   评论。选项字段是可选的。   密钥类型为“ecdsa-sha2-nistp256”,“ecdsa-sha2-nistp384”,“ecdsa-sha2-nistp521”,“ssh-ed25519”,“ssh-dss”或“ssh-rsa”;   注释字段不用于任何东西(但可能很方便   用户识别密钥)。 [...]选项(如果存在)包括   逗号分隔的选项规范。除了以外,不允许有空格   在双引号内。

如果我依赖这个文档并采用可能的关键类型,那么我 得到以下解决方案:

#!/usr/bin/env perl

use strict;
use warnings;

my $possible_types = join('|', qw(ecdsa-sha2-nistp256 
                                  ecdsa-sha2-nistp384 
                                  ecdsa-sha2-nistp521 
                                  ssh-ed25519 
                                  ssh-dss 
                                  ssh-rsa));

my $pattern = qr/^(?:(.*)\s+)?                 # optional options
                  ($possible_types) \s+ (\S+)  # mandatory type and key
                  (?:\s+(.*))?$/x;             # optional comment

while( <DATA> ) {
    if (/$pattern/) {
        my ($options, $type, $key, $comment) = ($1 // 'NONE', $2, $3, $4);
        print "options: '$options'\n";
        print "type:    '$type'\n";
        print "key:     '$key'\n";
        print "comment: '$comment'\n";
    } else {
        print "unrecognized line: $_";
    }
    print '-' x 30, "\n";
}

__DATA__
from="*.sales.example.net,!pc.sales.example.net" ssh-rsa AAAAB2...19Q== john@example.net
ssh-ed25519 AAA3Nzsdfsfsd...fdsXhsdfsfWqfw this is a comment
command="dump /home",no-pty,no-port-forwarding ssh-dss AAAAC3...51R== example.net
permitopen="192.0.2.1:80",permitopen="192.0.2.2:25" ssh-dss AAAAB5...21S==
tunnel="0",command="sh /etc/netstart tun0" ssh-rsa AAAA...== jane@example.net
restrict,command="uptime" ecdsa-sha2-nistp521 AAAA1C8...32Tv==
restrict,pty,command="nethack" ssh-rsa AAAA1f8...IrrC5== user@example.net

这是有效的,因为它需要六种可能的关键类型,然后在周围搜索:选项(如果有的话)必须是keytype之前的字符串;密钥类型后跟密钥(始终),并且可选择后跟注释。

但是,我并不喜欢这种方法,因为它具有硬编码的可能关键类型。对于您的输入,它打印:

options: 'from="*.sales.example.net,!pc.sales.example.net"'
type:    'ssh-rsa'
key:     'AAAAB2...19Q=='
comment: 'john@example.net'
------------------------------
options: 'NONE'
type:    'ssh-ed25519'
key:     'AAA3Nzsdfsfsd...fdsXhsdfsfWqfw'
comment: 'this is a comment'
------------------------------
options: 'command="dump /home",no-pty,no-port-forwarding'
type:    'ssh-dss'
key:     'AAAAC3...51R=='
comment: 'example.net'
------------------------------
options: 'permitopen="192.0.2.1:80",permitopen="192.0.2.2:25"'
type:    'ssh-dss'
key:     'AAAAB5...21S=='
comment: ''
------------------------------
options: 'tunnel="0",command="sh /etc/netstart tun0"'
type:    'ssh-rsa'
key:     'AAAA...=='
comment: 'jane@example.net'
------------------------------
options: 'restrict,command="uptime"'
type:    'ecdsa-sha2-nistp521'
key:     'AAAA1C8...32Tv=='
comment: ''
------------------------------
options: 'restrict,pty,command="nethack"'
type:    'ssh-rsa'
key:     'AAAA1f8...IrrC5=='
comment: 'user@example.net'
------------------------------

答案 1 :(得分:0)

这就是我提出的,它适用于我的测试数据。

  if (my ($koptions, $ktype, $kbase64, $kcomment) =$_ !~

       /^(?:((?:[!-~]|\s(?=.*"))+)\s+)? # optional key options
         ([a-z0-9_-]+)\s+               # key type followed by a space
         ([\.=a-z0-9\/+_-]+)            # RFC4253 base64 encoded key
         (?:\s+(.*))?$                  # optional comment
       /xxia) {             # ASCII, Case Insensitive, and exploded

    $koptions //= "NONE";
    $kcomment //= "NONE";
    print "\nkoptions are $koptions\n";
    print "ktype is $ktype\n";
    print "kbase64 is $kbase64\n";
    print "kcomment is $kcomment\n";
  } else {
    print "Incomprehensible line in ~/.ssh/authorized_keys!\n"
  }

示例文件:

ssh-rsa AAAAB3Nza...LiPk== user@example.net
from="*.sales.example.net,!pc.sales.example.net" ssh-rsa AAAAB2...19Q== john@example.net
ssh-ed25519 AAA3Nzsdfsfsd...fdsXhsdfsfWqfw this is a comment
command="dump /home",no-pty,no-port-forwarding ssh-dss AAAAC3...51R== example.net
permitopen="192.0.2.1:80",permitopen="192.0.2.2:25" ssh-dss AAAAB5...21S==
tunnel="0",command="sh /etc/netstart tun0" ssh-rsa AAAA...== jane@example.net
restrict,command="uptime" ecdsa-sha2-nistp521 AAAA1C8...32Tv==
restrict,pty,command="nethack" ssh-rsa AAAA1f8...IrrC5== user@example.net

我对风格或缺乏风格表示歉意。

有没有人有更优雅的东西?