line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package LWP::Auth_UA; |
2
|
|
|
|
|
|
|
$REVISION=q$Revision: 1.5 $ ; $VERSION = sprintf ( "%d.%02d", $REVISION =~ /(\d+).(\d+)/ ); |
3
|
2
|
|
|
2
|
|
174541
|
use LWP::UserAgent; |
|
2
|
|
|
|
|
151861
|
|
|
2
|
|
|
|
|
86
|
|
4
|
|
|
|
|
|
|
@ISA=qw(LWP::UserAgent); |
5
|
|
|
|
|
|
|
|
6
|
2
|
|
|
2
|
|
21
|
use strict; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
59
|
|
7
|
2
|
|
|
2
|
|
10
|
use warnings; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
571
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 NAME |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
LWP::Auth_UA.pm - a user agent which knows some authorisation tokens |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 SYNOPSIS |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
use LWP::Auth_UA.pm |
16
|
|
|
|
|
|
|
credentials ( { |
17
|
|
|
|
|
|
|
my_realm => { uri_re => "https://myhost.example.com", |
18
|
|
|
|
|
|
|
credential => "my_secret" } |
19
|
|
|
|
|
|
|
} ); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
$ua = LWP::Auth_UA->new; |
22
|
|
|
|
|
|
|
$request = HTTP::Request->new('GET', 'file://localhost/etc/motd'); |
23
|
|
|
|
|
|
|
$response = $ua->request($request); |
24
|
|
|
|
|
|
|
etc... |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
=head1 DESCRIPTION |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
This is a LWP user agent which is almost identical to the normal user |
29
|
|
|
|
|
|
|
agent (LWP::UserAgent) except that if it reaches a situation where it |
30
|
|
|
|
|
|
|
needs an authentication token then it will send a token which it has |
31
|
|
|
|
|
|
|
stored. |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
Storing authentication tokens in a file is inherently a security |
34
|
|
|
|
|
|
|
issue. This risk may, however, not be much higher than the one that |
35
|
|
|
|
|
|
|
you are currently carrying, so this can be useful. |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
This page describes how this works and how to ensure that the security |
38
|
|
|
|
|
|
|
risks you are taking on are not greater than are acceptable to you. |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
As with the rest of LinkController, there is no warantee. If you have |
41
|
|
|
|
|
|
|
an environment in which this might be a problem, you should definitely |
42
|
|
|
|
|
|
|
find someone to look over your installation and ensure that everything |
43
|
|
|
|
|
|
|
is done correctly. Of course, this is true of every piece of software |
44
|
|
|
|
|
|
|
you install. |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=head1 SECURITY RISKS |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
The fundamental security problem with this system is that the |
49
|
|
|
|
|
|
|
authentication token must be stored somewhere where the program can |
50
|
|
|
|
|
|
|
access it. This is because link-controller has to send the actual |
51
|
|
|
|
|
|
|
authentication token over the link to authenticate. Since it's very |
52
|
|
|
|
|
|
|
easy to monitor the inputs and outputs of a program, it's very easy to |
53
|
|
|
|
|
|
|
monitor this password. |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
This applies even if we keep the password in some encrypted form, |
56
|
|
|
|
|
|
|
since we then have to store the decryption key in the program which |
57
|
|
|
|
|
|
|
can then be found and used to decrypt the key. |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
So there are only two possible defenses: |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=over 4 |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=item * |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
make sure that the program data remains secret |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=item * |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
make sure that the passwords the program has can't do any real damage |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=back |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
We demand permissions on our files which protect against accidental |
74
|
|
|
|
|
|
|
disclosure by encouraging the user to be more secure. |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
Making sure that the program can't do any damage is normally achieved |
77
|
|
|
|
|
|
|
by giving it a dedicated account which has only read only privilages |
78
|
|
|
|
|
|
|
and, preferably, can only use it's privilages from a specified system |
79
|
|
|
|
|
|
|
which will be the host on which the link checking is run. |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=head2 Accidental Sending of Tokens |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
Another authentication risk is that the system will send it to a |
84
|
|
|
|
|
|
|
server which is trying to trick it. This is again difficult to |
85
|
|
|
|
|
|
|
protect against. The only solution in this case is to ensure that the |
86
|
|
|
|
|
|
|
regular expression used for limiting the URI matches only host names |
87
|
|
|
|
|
|
|
which are under the control of the body responsible for handing out |
88
|
|
|
|
|
|
|
the authentication token. |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
The security of this system is not of course perfect. If we can |
91
|
|
|
|
|
|
|
pretend to be the host that we are meant to send the authentication |
92
|
|
|
|
|
|
|
token to then we will can trick the user agent into sending the token. |
93
|
|
|
|
|
|
|
Remember that the hostname being used is the one in the URL we are |
94
|
|
|
|
|
|
|
trying to examine, so the protection against this is having a secure |
95
|
|
|
|
|
|
|
and correct DNS system and ensuring that we have a secure IP |
96
|
|
|
|
|
|
|
connection to the end host. |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=head2 Sending of Tokens over Insecure protocols |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
If an insecure protocol like HTTP is used for sending an |
101
|
|
|
|
|
|
|
authentication token, then it is possible for someone to listen to the |
102
|
|
|
|
|
|
|
transaction and record the token for later use. |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
The protection against this is to switch over to only using secure |
105
|
|
|
|
|
|
|
protocols and hard wire the protocol name into the URI regular expression. |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=cut |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub get_basic_credentials { |
110
|
4
|
|
|
4
|
1
|
353889
|
my $self=shift; |
111
|
4
|
|
|
|
|
8
|
my $realm=shift; |
112
|
4
|
|
|
|
|
6
|
my $uri=shift; |
113
|
4
|
|
|
|
|
6
|
my $proxy=shift; |
114
|
4
|
|
|
|
|
8
|
my $credentials=$self->{"Auth_UA-credentials"}; |
115
|
4
|
100
|
|
|
|
15
|
return undef unless defined $credentials; |
116
|
3
|
|
|
|
|
5
|
my $rec=$credentials->{$realm}; |
117
|
3
|
100
|
|
|
|
9
|
return undef unless defined $rec; |
118
|
2
|
|
|
|
|
4
|
my $re=$rec->{uri_re}; |
119
|
2
|
100
|
|
|
|
24
|
return undef unless $uri =~ m/$re/; |
120
|
1
|
|
|
|
|
5
|
return $rec->{credential} |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
sub auth_ua_credentials { |
124
|
1
|
|
|
1
|
0
|
4595
|
my $self=shift; |
125
|
1
|
50
|
|
|
|
7
|
return $self->{"Auth_UA-credentials"} unless @_; |
126
|
1
|
|
|
|
|
3
|
my $cred=shift; |
127
|
1
|
|
|
|
|
3
|
$self->{"Auth_UA-credentials"} = $cred; |
128
|
1
|
|
|
|
|
3
|
return $cred; |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub delete_brain_dead_credentials { |
132
|
1
|
|
|
1
|
0
|
20
|
my $self=shift; |
133
|
1
|
|
|
|
|
2
|
my $cred=shift; |
134
|
1
|
50
|
|
|
|
5
|
$cred=$self->{"Auth_UA-credentials"} unless defined $cred; |
135
|
1
|
50
|
|
|
|
4
|
return undef unless defined $cred; |
136
|
1
|
|
|
|
|
6
|
foreach my $key ( keys %$cred ) { |
137
|
2
|
|
|
|
|
5
|
my $rec=$cred->{$key}; |
138
|
2
|
|
|
|
|
4
|
my $re=$rec->{uri_re}; |
139
|
|
|
|
|
|
|
( "http://3133t3hax0rs.rhere.com" =~ m/$re/ |
140
|
|
|
|
|
|
|
or "http://3133t3hax0rs.rhere.com/secretstuff/www.goodplace.com/" =~ m/$re/ ) |
141
|
2
|
100
|
66
|
|
|
56
|
and do { |
142
|
1
|
|
|
|
|
16
|
warn "Deleting credential with dangerous URI RE $re in Auth_UE for real $key"; |
143
|
1
|
|
|
|
|
9
|
delete $cred->{$key}; |
144
|
|
|
|
|
|
|
}; |
145
|
|
|
|
|
|
|
} |
146
|
1
|
|
|
|
|
4
|
return $cred; |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# sub aua_load_credentials { |
151
|
|
|
|
|
|
|
# my $self=shift; |
152
|
|
|
|
|
|
|
# my $file=$self->{Auth_UA-authfile}; |
153
|
|
|
|
|
|
|
# open my $cred, $file; |
154
|
|
|
|
|
|
|
# while ( <$cred> ) { |
155
|
|
|
|
|
|
|
# my ($realm, $auth, $uri_re) = m/ |
156
|
|
|
|
|
|
|
# }; |
157
|
|
|
|
|
|
|
# } |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# sub aua_authfile { |
160
|
|
|
|
|
|
|
# my $self=shift; |
161
|
|
|
|
|
|
|
# return $self->{Auth_UA-authfile} unless @_; |
162
|
|
|
|
|
|
|
# $self->{Auth_UA-authfile} = shift; |
163
|
|
|
|
|
|
|
# } |