summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Prykop <jonathan@freeside.biz>2015-12-07 17:46:45 -0600
committerJonathan Prykop <jonathan@freeside.biz>2015-12-14 20:22:22 -0600
commit5a813d91f3d4b1c6eff81dfa9c88e2b587442984 (patch)
tree69b4dd20858c739a07959c887c06bc9b36486f82
parent8cd6e05d5d906da6b001b36bab5aa87ecdfca944 (diff)
RT#29354: Password Security in Email [customer fields, images, js files]
-rw-r--r--FS/FS/Password_Mixin.pm34
-rw-r--r--FS/FS/svc_acct.pm1
-rw-r--r--fs_selfservice/FS-SelfService/cgi/add_password_validation.js (renamed from fs_selfservice/FS-SelfService/cgi/add_password_validation.html)16
-rw-r--r--fs_selfservice/FS-SelfService/cgi/change_password.html10
-rw-r--r--fs_selfservice/FS-SelfService/cgi/images/error.pngbin0 -> 666 bytes
-rw-r--r--fs_selfservice/FS-SelfService/cgi/images/tick.pngbin0 -> 537 bytes
-rw-r--r--fs_selfservice/FS-SelfService/cgi/process_forgot_password.html19
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/selfservice.cgi9
-rw-r--r--fs_selfservice/FS-SelfService/cgi/send_xmlhttp.js (renamed from fs_selfservice/FS-SelfService/cgi/send_xmlhttp.html)2
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/signup.cgi28
-rwxr-xr-xfs_selfservice/FS-SelfService/cgi/signup.html12
-rw-r--r--httemplate/elements/validate_password.html8
12 files changed, 85 insertions, 54 deletions
diff --git a/FS/FS/Password_Mixin.pm b/FS/FS/Password_Mixin.pm
index 3129366..834fd6f 100644
--- a/FS/FS/Password_Mixin.pm
+++ b/FS/FS/Password_Mixin.pm
@@ -67,6 +67,40 @@ sub is_password_allowed {
return '' unless $self->get($self->primary_key); # for validating new passwords pre-insert
+ #check against customer fields
+ my $cust_main = $self->cust_main;
+ if ($cust_main) {
+ my @words;
+ # words from cust_main
+ foreach my $field ( qw( last first daytime night fax mobile ) ) {
+ push @words, split(/\W/,$cust_main->get($field));
+ }
+ # words from cust_location
+ foreach my $loc ($cust_main->cust_location) {
+ foreach my $field ( qw(address1 address2 city county state zip) ) {
+ push @words, split(/\W/,$loc->get($field));
+ }
+ }
+ # words from cust_contact & contact_phone
+ foreach my $contact (map { $_->contact } $cust_main->cust_contact) {
+ foreach my $field ( qw(last first) ) {
+ push @words, split(/\W/,$contact->get($field));
+ }
+ # not hugely useful right now, hyphenless stored values longer than password max,
+ # but max will probably be increased eventually...
+ foreach my $phone ( qsearch('contact_phone', {'contactnum' => $contact->contactnum}) ) {
+ push @words, split(/\W/,$phone->get('phonenum'));
+ }
+ }
+ # do the actual checking
+ foreach my $word (@words) {
+ next unless length($word) > 2;
+ if ($password =~ /$word/i) {
+ return qq(Password contains account information '$word');
+ }
+ }
+ }
+
my $no_reuse = 3;
# allow override here if we really must
diff --git a/FS/FS/svc_acct.pm b/FS/FS/svc_acct.pm
index 38cebc1..53b12f1 100644
--- a/FS/FS/svc_acct.pm
+++ b/FS/FS/svc_acct.pm
@@ -2686,6 +2686,7 @@ sub password_svc_check {
my ($self, $password) = @_;
foreach my $field ( qw(username finger) ) {
foreach my $word (split(/\W+/,$self->get($field))) {
+ next unless length($word) > 2;
if ($password =~ /$word/i) {
return qq(Password contains account information '$word');
}
diff --git a/fs_selfservice/FS-SelfService/cgi/add_password_validation.html b/fs_selfservice/FS-SelfService/cgi/add_password_validation.js
index e349fd7..e2e3227 100644
--- a/fs_selfservice/FS-SelfService/cgi/add_password_validation.html
+++ b/fs_selfservice/FS-SelfService/cgi/add_password_validation.js
@@ -1,5 +1,4 @@
-<SCRIPT>
-function add_password_validation (fieldid) {
+function add_password_validation (fieldid,nologin) {
var inputfield = document.getElementById(fieldid);
inputfield.onchange = function () {
var fieldid = this.id+'_result';
@@ -11,19 +10,22 @@ function add_password_validation (fieldid) {
}
if (this.value) {
resultfield.innerHTML = '<SPAN STYLE="color: blue;">Validating password...</SPAN>';
+ var action = nologin ? 'validate_password_nologin' : 'validate_password';
send_xmlhttp('selfservice.cgi',
- ['action','validate_password','fieldid',fieldid,'svcnum',svcnum,'check_password',this.value],
+ ['action',action,'fieldid',fieldid,'svcnum',svcnum,'check_password',this.value],
function (result) {
result = JSON.parse(result);
var resultfield = document.getElementById(result.fieldid);
if (resultfield) {
+ var errorimg = '<IMG SRC="images/error.png" style="width: 1em; display: inline-block; padding-right: .5em">';
+ var validimg = '<IMG SRC="images/tick.png" style="width: 1em; display: inline-block; padding-right: .5em">';
if (result.valid) {
- resultfield.innerHTML = '<SPAN STYLE="color: green;">Password valid!</SPAN>';
+ resultfield.innerHTML = validimg+'<SPAN STYLE="color: green;">Password valid!</SPAN>';
} else if (result.error) {
- resultfield.innerHTML = '<SPAN STYLE="color: red;">'+result.error+'</SPAN>';
+ resultfield.innerHTML = errorimg+'<SPAN STYLE="color: red;">'+result.error+'</SPAN>';
} else {
result.syserror = result.syserror || 'Server error';
- resultfield.innerHTML = '<SPAN STYLE="color: red;">'+result.syserror+'</SPAN>';
+ resultfield.innerHTML = errorimg+'<SPAN STYLE="color: red;">'+result.syserror+'</SPAN>';
}
}
}
@@ -33,4 +35,4 @@ function add_password_validation (fieldid) {
}
};
}
-</SCRIPT>
+
diff --git a/fs_selfservice/FS-SelfService/cgi/change_password.html b/fs_selfservice/FS-SelfService/cgi/change_password.html
index ef66554..879faf2 100644
--- a/fs_selfservice/FS-SelfService/cgi/change_password.html
+++ b/fs_selfservice/FS-SelfService/cgi/change_password.html
@@ -28,11 +28,11 @@
<TD>
<INPUT ID="new_password" TYPE="password" NAME="new_password" SIZE="18">
<DIV ID="new_password_result"></DIV>
-<%= include('send_xmlhttp') %>
-<%= include('add_password_validation') %>
-<SCRIPT>
-add_password_validation('new_password');
-</SCRIPT>
+ <SCRIPT SRC="send_xmlhttp.js"></SCRIPT>
+ <SCRIPT SRC="add_password_validation.js"></SCRIPT>
+ <SCRIPT>
+ add_password_validation('new_password');
+ </SCRIPT>
</TD>
</TR>
diff --git a/fs_selfservice/FS-SelfService/cgi/images/error.png b/fs_selfservice/FS-SelfService/cgi/images/error.png
new file mode 100644
index 0000000..628cf2d
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/images/error.png
Binary files differ
diff --git a/fs_selfservice/FS-SelfService/cgi/images/tick.png b/fs_selfservice/FS-SelfService/cgi/images/tick.png
new file mode 100644
index 0000000..a9925a0
--- /dev/null
+++ b/fs_selfservice/FS-SelfService/cgi/images/tick.png
Binary files differ
diff --git a/fs_selfservice/FS-SelfService/cgi/process_forgot_password.html b/fs_selfservice/FS-SelfService/cgi/process_forgot_password.html
index ec672c8..da6fc8d 100644
--- a/fs_selfservice/FS-SelfService/cgi/process_forgot_password.html
+++ b/fs_selfservice/FS-SelfService/cgi/process_forgot_password.html
@@ -15,6 +15,7 @@
<INPUT TYPE="hidden" NAME="session_id" VALUE="<%= $session_id %>">
<INPUT TYPE="hidden" NAME="agentnum" VALUE="<%= $agentnum %>">
+<DIV STYLE="background: <%= $box_bgcolor || '#c0c0c0' %>">
<TABLE BGCOLOR="<%= $box_bgcolor || '#c0c0c0' %>" BORDER=0 CELLSPACING=2 CELLPADDING=0>
<%= if (!$error) {
@@ -23,16 +24,27 @@
<TR>
<TH ALIGN="right">New password: </TH>
- <TD><INPUT TYPE="password" NAME="new_password" SIZE="18"></TD>
+ <TD>
+ <INPUT ID="new_password" TYPE="password" NAME="new_password" SIZE="18">
+ </TD>
+ <TD>
+ <SPAN ID="new_password_result"></SPAN>
+ <SCRIPT SRC="send_xmlhttp.js"></SCRIPT>
+ <SCRIPT SRC="add_password_validation.js"></SCRIPT>
+ <SCRIPT>
+ add_password_validation('new_password',true);
+ </SCRIPT>
+ </TD>
</TR>
<TR>
<TH ALIGN="right">Re-enter new password: </TH>
<TD><INPUT TYPE="password" NAME="new_password2" SIZE="18"></TD>
+ <TD></TD>
</TR>
-
<TR>
- <TD COLSPAN=2 ALIGN="center"><INPUT TYPE="submit" VALUE="Change password"></TD>
+ <TD COLSPAN="2" ALIGN="center"><INPUT TYPE="submit" VALUE="Change password"></TD>
+ <TD></TD>
</TR>
END
@@ -40,6 +52,7 @@ END
%>
</TABLE>
+</DIV>
</FORM>
<%= $body_footer %>
diff --git a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
index 5845122..aff9bca 100755
--- a/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
+++ b/fs_selfservice/FS-SelfService/cgi/selfservice.cgi
@@ -95,6 +95,7 @@ my @nologin_actions = (qw(
process_forgot_password
do_process_forgot_password
process_forgot_password_session
+ validate_password_nologin
));
push @actions, @nologin_actions;
my %nologin_actions = map { $_=>1 } @nologin_actions;
@@ -1132,6 +1133,14 @@ sub validate_password {
)
}
+sub validate_password_nologin {
+ $action = 'validate_password'; #use same landing page
+ validate_passwd(
+ map { $_ => scalar($cgi->param($_)) }
+ qw( fieldid check_password )
+ )
+}
+
#--
sub do_template {
diff --git a/fs_selfservice/FS-SelfService/cgi/send_xmlhttp.html b/fs_selfservice/FS-SelfService/cgi/send_xmlhttp.js
index ac85cb2..e299168 100644
--- a/fs_selfservice/FS-SelfService/cgi/send_xmlhttp.html
+++ b/fs_selfservice/FS-SelfService/cgi/send_xmlhttp.js
@@ -1,4 +1,3 @@
-<SCRIPT>
function rs_init_object () {
var A;
try {
@@ -41,5 +40,4 @@ function send_xmlhttp (url,args,callback) {
xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xmlhttp.send(content);
}
-</SCRIPT>
diff --git a/fs_selfservice/FS-SelfService/cgi/signup.cgi b/fs_selfservice/FS-SelfService/cgi/signup.cgi
index 072ce96..817fdd3 100755
--- a/fs_selfservice/FS-SelfService/cgi/signup.cgi
+++ b/fs_selfservice/FS-SelfService/cgi/signup.cgi
@@ -508,31 +508,3 @@ use FS::SelfService qw( regionselector expselect popselector domainselector
didselector
);
-sub add_password_validation {
- my $fieldid = shift;
- my $out = '';
- if ((-e './send_xmlhttp.html') && (-e './add_password_validation.html')) {
- my $template = new Text::Template( TYPE => 'FILE',
- SOURCE => "./send_xmlhttp.html",
- DELIMITERS => [ '<%=', '%>' ],
- UNTAINT => 1,
- )
- or die $Text::Template::ERROR;
- $out .= $template->fill_in( PACKAGE => 'FS::SelfService::_signupcgi' );
- $template = new Text::Template( TYPE => 'FILE',
- SOURCE => "./add_password_validation.html",
- DELIMITERS => [ '<%=', '%>' ],
- UNTAINT => 1,
- )
- or die $Text::Template::ERROR;
- $out .= $template->fill_in( PACKAGE => 'FS::SelfService::_signupcgi' );
- $out .= <<ENDOUT;
-<SCRIPT>
-add_password_validation('$fieldid');
-</SCRIPT>
-ENDOUT
- }
- return $out;
-}
-
-
diff --git a/fs_selfservice/FS-SelfService/cgi/signup.html b/fs_selfservice/FS-SelfService/cgi/signup.html
index 5900ba6..def5299 100755
--- a/fs_selfservice/FS-SelfService/cgi/signup.html
+++ b/fs_selfservice/FS-SelfService/cgi/signup.html
@@ -386,12 +386,12 @@ ENDOUT
<TD ALIGN="right">Password</TD>
<TD>
<INPUT ID="new_password" TYPE="password" NAME="_password" VALUE="$_password">
- <DIV ID="new_password_result"></DIV>
-ENDOUT
-
- $OUT .= add_password_validation('new_password');
-
- $OUT .= <<ENDOUT;
+ <SPAN ID="new_password_result"></SPAN>
+ <SCRIPT SRC="send_xmlhttp.js"></SCRIPT>
+ <SCRIPT SRC="add_password_validation.js"></SCRIPT>
+ <SCRIPT>
+ add_password_validation('new_password',true);
+ </SCRIPT>
</TD>
</TR>
<TR>
diff --git a/httemplate/elements/validate_password.html b/httemplate/elements/validate_password.html
index fd2cb6c..a488c4f 100644
--- a/httemplate/elements/validate_password.html
+++ b/httemplate/elements/validate_password.html
@@ -32,13 +32,15 @@ function add_password_validation (fieldid) {
result = JSON.parse(result);
var resultfield = document.getElementById(result.fieldid);
if (resultfield) {
+ var errorimg = '<IMG SRC="<% $p %>images/error.png" style="width: 1em; display: inline-block; padding-right: .5em">';
+ var validimg = '<IMG SRC="<% $p %>images/tick.png" style="width: 1em; display: inline-block; padding-right: .5em">';
if (result.valid) {
- resultfield.innerHTML = '<SPAN STYLE="color: green;">Password valid!</SPAN>';
+ resultfield.innerHTML = validimg+'<SPAN STYLE="color: green;">Password valid!</SPAN>';
} else if (result.error) {
- resultfield.innerHTML = '<SPAN STYLE="color: red;">'+result.error+'</SPAN>';
+ resultfield.innerHTML = errorimg+'<SPAN STYLE="color: red;">'+result.error+'</SPAN>';
} else {
result.syserror = result.syserror || 'Server error';
- resultfield.innerHTML = '<SPAN STYLE="color: red;">'+result.syserror+'</SPAN>';
+ resultfield.innerHTML = errorimg+'<SPAN STYLE="color: red;">'+result.syserror+'</SPAN>';
}
}
}