Moodle runs fine under https ...
Using this theoretical $CFG->loginpage that points to the https://... version would ....
in login/index_form.html:
<form action="<?php echo $CFG->loginpage ?>/login/index.php" method="post" name="form" id="form">
instead of:
<form action="index.php" method="post" name="form" id="form">
be the correct place to ensure a secure login?
Of course for this to work cleanly secureforms would need to be switched off which might defeat the purpose somewhat.
Hi all,
Just a quick question? How secure is Moodle actually?Assuming you are hosting on an ISP, running on Apache, mysql with https:
- Can other persons (without a userid) get into a moodle course?
- If I upload confidential files, can they view these files?
- Are the files uploaded indexed by a search engine, so other people can get a link to a file in my courses, other than via the standard log in?
The reason I'm asking is that I would like to use a special course of moodle to upload "business critical" files. I don't want anybody to get in and view these files except from myself. Moodle will be my document management system, because I'm tired of Bill Gates lousy File sytem. Everytime a folder is migrated, my links and shortcuts are broken.
Thanks,
Runy
Yes, Yes, Yes. Thanks you all for your reply and, I'll go for it
Any registered staff or student can get in and view or download the files, but no one without a valid ID would be able to do anything.
Students cannot change anything, theoretically the staff can, but only a few have had the relevant training, so they are set as "editing" teachers, the rest as "non-editing".
Works very well.
Oxford Beardie
Would it be difficult to implement this as a standard feature? I see that no one has stepped forward to do this since the time of Martin's response (Nov. 2003).
Martin, where would this fit in to your priorities? Any other takers? I'm afraid that my technical background isn't up to the task.
It's quite possible and relatively easy to put all of Moodle under a https server now - it will work fine and I don't find performance to be affected THAT much by having every page encyrypted (then again I'm on ADSL).
If performance is an issue, then you have to run TWO servers, one http and one https, and they have to share session information (on the server side) so that the session cookie generated on the https server isent to the browser, which then sends it back to the http server which then finds the session info and continues the session cleanly.
The only Moodle mod needed would be a variable to specify the https login page and then a little code to make sure it gets used every time a redirect to the login page (ie /login/index.php) is performed. If the wwwroot of Moodle is set to be the http server then it should go back to http automatically after the login.
We use a secure server for our entire Moodle installation. There is no special setup for running Moodle under https as opposed to http. Our sysdadmin estimates that the performance penalty for doing this is less than 10%. We bought our server certificate from: http://www.comodo.net/. It costs us $50 per annum, hardly $$$.
However, I've just added a new form of authentication to our Moodle, entitled "Custom authentication", which among other things allows having a secure login page, but running the rest of Moodle under a nonsecure web server. I'll be sending my mods to Martin for his consideration for inclusion in version 1.2.
There is a solution to prevent this, even when using normal HTTP. However, it requires that session information is kept on the server itself, and not in cookies (which may be a big performance hit on the server if you have 1000s of users in at once). I actually have code which does exactly that, and use it in the login screen of my home-made application framework. It goes something like this:
- The user's browser contacts the server. The server sees the user has no session information and prepares for login. The server produces a random number, stores it in the user's session variables and sends it back with http.
- The user's login page is displayed. The user writes username and password and submits.
- The page has an onSubmit event, which runs some JavaScript code. The code calculates the MD5 hash of the password and sets the value of some hidden field to it. The "clear" password field (which the user just set) is set to an empty string.
- The cleartext username, MD5 of password, and cleartext random number (which the server sent us) are returned with the HTTP form.
- The server checks to see if the random number is the same as in its local session variables. Then it checks the username and MD5 of password (remember passwords are stored as hashes in the database). If everything matches, the user is authenticated. We can now unset the random number. If not, change the random number to something else and repeat ad nauseum.
The advantages of this method are:
- ADOdb (which Moodle uses) makes it very easy to have session vars in MySQL. There is the matter of the performance hit, but in my case there is no contest, since using cookies exposes you to a whole new class of problems.
- It's very easy to implement (just a little JavaScript and 10 lines of code in your page, the server-side logic is about one pageful of self-evident code).
- It's secure against eavesdropping (the attacker knows the MD5 of your password, but doesn't know your password).
- It's secure against replay attacks (even if later he tries to use spoofed TCP packets, he won't be able to login after your session has expired. The random number he would have to send has changed).
There are two disadvantages:
- The performance hit.
- You cannot use this method if the server needs the cleartext password for some reason (e.g. to authenticate you with another server). I 'm not familiar with how LDAP works, but it probably falls in this case.
I hope that someone finds some of this helpful!
http://pajhome.org.uk/crypt/md5/
The server-side session stuff is no trouble, as we already have that set up (just set/unset variables in $SESSION variable), and we can put a refresh of 15 minutes or so on the login page to make sure the session stays active. To start with it only makes sense when using internal authentication, I think.
It does make Javascript a mandatory thing for students, which currently is not the case, but I think most admins would be happy to make this tradeoff (it will be an option, of course).
That's where I got the scripts when I read about and decided to use this scheme too!
So, since you 're interested:
Javascript and HTML (for the login form):
<script type='text/javascript'>
function onLoginSubmit() {
var f = document.forms[0];
if (!f) {alert('Your browser is not compatible.'); return false;}
f.encoded_pass.value = calcMD5(f.passwd.value);
f.encoded_rand.value = calcMD5(f.randval.value);
f.passwd.value='';
return true;
}
</script>
HTML editor workaround: Intentional blank space left between "on" and "submit"
<form on submit="return onLoginSubmit();" name="logon" method="post" action="index.php">
<!--
Other fields and submit button here. You will need to match the fieldnames
with those present in the onLoginSubmit() function above.
-->
<input type='hidden' name='encoded_pass' value='' />
<input type='hidden' name='encoded_rand' value='' />
<input type='hidden' name='randval' value = '{$SESSION_RANDVAL}' />
<input type='hidden' name='action' value='login' />
</form>
PHP code (login module):
<?php
if(!isset($_REQUEST['op'])) $_REQUEST['op'] = ''; // Gets rid of an E_NOTICE just below
switch($_REQUEST['op']) {
default:
case 'login':
if(!$GLOBALS['APP']->UserLoggedIn()) {
op_login();
}
else {
$GLOBALS['APP']->ModuleActivate();
}
break;
case 'logout':
if($GLOBALS['APP']->UserLoggedIn()) op_logout();
else op_login();
break;
}
function op_login()
{
if(isset($_POST['encoded_pass']) &&
isset($_POST['encoded_rand']) &&
isset($_SESSION['randval']) &&
$_POST['encoded_rand'] == md5($_SESSION['randval']) &&
!empty($_POST['username']))
{
if(!ereg('[a-z0-9]', $_POST['encoded_pass'])) {
$GLOBALS['APP']->ModuleActivate('reset');
}
if(ereg('['"]', $_POST['username'])) {
$GLOBALS['APP']->ModuleActivate('reset');
}
$userinfo = $GLOBALS['DBCONN']->GetRow('SELECT UserID, Username FROM '.
DB_Table('users').' WHERE Password=''.$_POST['encoded_pass'].
'' AND Username=''.$_POST['username'].''');
if(!empty($userinfo) && $userinfo['Username'] == $_POST['username'])
{
// Login successful
unset($_SESSION['randval']);
$_SESSION['user'] = $userinfo['Username'];
$_SESSION['userID'] = $userinfo['UserID'];
$GLOBALS['APP']->ModuleActivate(); // Default module
}
else
{
// Login failed
// display some message
$GLOBALS['ERROR_MSGS'][$_REQUEST['action']][] =
'Bad username/password';
$GLOBALS['SMARTY']->assign(array(
'SESSION_RANDVAL' => $_SESSION['randval'],
));
}
}
else
{
// Display login form
if(!isset($_SESSION['randval'])) {
mt_srand ((double) microtime() * 1000000);
$_SESSION['randval'] = mt_rand();
}
$GLOBALS['SMARTY']->assign(array(
'SESSION_RANDVAL' => $_SESSION['randval'],
));
}
}
function op_logout()
{
$_SESSION = array();
session_destroy();
$GLOBALS['APP']->ModuleActivate($GLOBALS['module']);
}
?>
General Notes:
I 've noticed that my strings have been unslashed. Keep this in mind, you 'll get some syntax errors as it is (single quotes within singly quoted strings).
$GLOBALS['DBCONN'] is an ADOdb connection.
$GLOBALS['SMARTY'] is... what its name says! You 'll have to change things a bit, and of course the random number value in the HTML form will have to be given "by hand".
$GLOBALS['APP'] is my Application object. In this snippet only 2 methods are exposed:
UserLoggedIn() returns true if there is session information and it says that this is a logged-in user.
ModuleActivate($module) loads and activates a module. Without arguments it activates the "main" module (this is what I do when the user successfully logs in). The ModuleActivate('reset') call just displays a screen which says something to the lines of "Security precaution: your session has been reset. Please login in again." and destroys all session variables. (This means that on the next login page access, a new random number will be assigned).
Set up the two sites so that the sites share exactly the same directory, and use the setting on admin >> configuration >> variables called "loginhttps" ... it will redirect people to the https page for the login, and the redirect them back afterwards.
Also when I do find it should I have a complete copy of moodle on the secure server or just the login and/or auth directory?
Thanks,
Paolo
$CFG->loginhttps = true;
in the config.php file.
The best way is NOT to have any separate copies of any files. Have one single copy, and set up your server to use that same set of files for access on port 80 (http) and port 443 (https).
Hello Martin,
First, I just would like to say thanks for leading the way in creating such a wonderful virtual learning environment!!! (this is my first post to the Moodle community)
I recently installed Moodle 1.4.2. and I did notice the loginhttps variable on the admin configuration page. However, it was locked and I couldn't change the setting. Is this by design? If yes, why?
The web hosting company that I use does support https. I just have to name a folder in my wwwroot directory called ssl and place any page I want encrypted into this ssl folder. Can I just move the login/index.php page to this ssl folder? If yes, what other changes would I have to make to get this to work (secure the login screen)?
Best regards,
Ray
A good system is one that is easy to use and understand by the one at the keyboard, developers will do good to remember this. If a folder has too many files and complexed coding then its to difficult
That's my $1.98 cents worth lol :D