laurakgibbs,
Let me start with I saw some of your stuff the other day and visited your site and saw your widgets page. I was especially intrigued by your teacher-does-no-grading approach. Anyway, I don't want to hijack the thread, just wanted to say you've done a lot of interesting things and are doing a wonderful job documenting it for other people.
I'll also have to say I cringed when I read your statements about using widgets with other learning management systems and not understanding why Canvas won't allow it. Hopefully this message will help clear up the reasoning. I'll also say that I'm not a Canvas employee, although I do enjoy their conferences, and they probably have reasoning that goes far beyond anything I can suppose. And while I know a little about security, there are other people much more knowledgeable than I am that could probably provide a more in-depth explanation.
I'm not a tl;dr kind of guy (I think there's a meme somewhere about that), but the short version is:
The file that you uploaded with JavaScript in it is not the security issue when viewed from within Files that it is when viewed from a Content Page. Therefore, Canvas does not need to sanitize it within the Files section, but they do for Content Pages.
Here is an example file I created.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>HTML File with JavaScript Embedded</title>
<script>
alert('I am clever and will hijack your system.');
console.log(ENV);
</script>
</head>
<body>
<h1>HTML File with JavaScript Embedded</h1>
<p>This is an HTML file with a JavaScript script embedded in it</p>
</body>
</html>
The alert() just pops a message up on the browser window and waits. The console.log() sends a message to the browser's console log, which can be seen in most browsers with F12. I use it a lot for debugging things, but in production it probably shouldn't be used. I used those two commands to do some JavaScript without actually doing any damage.
The ENV variable that's it's logging to the Console is part of the environment that is exposed by Canvas when you are inside Canvas. It includes things like your timezone, your name, your user ID, certain features that are enabled, etc. It's not so much the information that's contained in there as the fact that you can see it that is worrisome. If you can see that and you can run JavaScript on the page, then you can do things as that user without any further steps. I do quite a bit of this with the user script Canvancements that I write. Things like sorting the roster, downloading the access information for an entire class, or the rubric importer I just released on Monday.
If a script was poorly written, and many are (we've probably all seen the "this page is unresponsive" errors), then allowing it to run on the page could make Canvas unresponsive or slow. The user isn't going to blame the script that the instructor put on the page for the problem, they just know it happened in Canvas, so Canvas is going to get the blame. By requiring custom JavaScript to be added at the account or sub-account level, they're hoping that the code has been vetted and checked, rather than just some widget that someone found on the internet and it looks cool but they don't code themselves so they didn't check it out to make sure it was safe.
If you were malicious, you could do other things, like automatically submit a quiz and keep the user from being able to turn things in. You could set it to change the password so the person couldn't log in or change it to something so you could log in and then do anything you wanted as that student. If you're a prankster more than someone malicious, you could change the language so they couldn't read anything on the page. You could hijack their communications and send out emails to everyone in their courses and get the real owner banned. You could set it to display pop-ups of advertising or warn that your computer is infected and you'll need to send money to get it restored to normal. If someone viewed the page (or file) who had elevated rights, like an admin, then real damage could be done. The malicious person could go through and start deleting files, pages, or even courses. And while there is the wonderful /undelete route for most things, this could cause serious disruption.
In other words, my console.log() could have easily been malicious code and that's part of why Canvas doesn't allow it on content pages. A teacher might never do that, but a student could easily insert something into a discussion post and then anyone who views the discussion would be hit with whatever payload it had.
Now to talk about files.
Here's that file I wrote sitting in my files folder of my sandbox course on my beta instance of Canvas.
When I click on it I get this
The alert() function is actually blocking, which means that execution stops at that point, which is why the rest of the page did get loaded until I click the OK (I did this to make the point about poorly written code could cause problems). After I clicked OK, then I got the rest of the page to show.
If I look at my browser's console log (F12) with the JavaScript errors enabled, I get this:
However, if I manually ask it to show the ENV variable, I get
The ReferenceError: ENV is not defined happens because you're not actually inside the Canvas environment when you're viewing that file.
To the normal user, that last sentence is absurd sounding because they can see the Canvas menu and they clicked on the file from within Canvas, so in their mind, they're in Canvas. That's why it's so important that Canvas not allow scripts -- it's a trusted environment. Users are going to trust anything it does because the school said to use it. If a message pops up within Canvas that says "There has been a problem with your financial aid -- enter your SSN and credit card information so we can fix the problem." some students are going to fall for it.
But if you look at the code using the inspector, you'll see something like this:
Yes, that's an iframe that the document is wrapped inside. The iframe provides isolation from the parent window (the Canvas application) so that it can't interact with it (there are scripts that allow this, but they're not loaded unless someone has modified their custom JavaScript - H5P suggests doing this with their content).
The parent window (Canvas) can see the contents of the iFrame, and I use that in my QuizWiz user script so that I can add buttons to the page that's loaded to speed up the process. But the iframe can't see the parent, which is why people keep on asking if there's any way to resize embedded content, like SCORM, to make it take up the entire screen instead of being stuck in the pre-defined size that is too small to be usable or adds scrollbars if set too large.
It's a good thing that the content is contained within an iframe because it would be very difficult for Canvas to scan the contents of a file for malicious content -- that would be like having a built-in virus checker, which has been a feature request if I remember correctly. Antivirus definitions files are changed multiple times throughout the day and even though I scan my email attachments folder when the files are downloaded and again every morning, it's often a few days or weeks before the virus is detected. Inside an HTML file, the JavaScript could be obfuscated, minimized, or otherwise altered so that it doesn't appear malicious until it actually runs. It's really going to be difficult to impossible to protect against that while running in the Canvas environment and not an iframe, so it's safest to use the iframe. On the other hand, the content in a content page is much easier to handle since it needs to be HTML and for accessibility purposes, it needs to be well-formed HTML. Canvas can strip out the things that are known to be bad or potentially dangerous, or better yet, allow just the things that are known to work well. That's better from a security perspective because a list of blocked elements might miss something or a vulnerability might be found that wasn't on the original list and cause a rush to get it handled before it does damage; whereas a list of allowed elements says these are known to be safe. Only allowing certain things to be changed by the designer/instructor is also good for the consistent look and feel of the Canvas environment, which in turn helps students. (Yesterday, I watched Jared Stein's Ask Me Anything presentation and I feel like I just went through five levels of why -- even things that hadn't quite gelled for me became all the more apparent as I wrote this).
In summary:
Including scripts is a security risk on a content page because it's part of the actual page and runs within a Canvas environment with the permissions of the user logged into Canvas and could cause serious problems if it were allowed. Canvas is right to strip out script tags at that point for the protection of the users and the environment.
However, when previewing the file, it's wrapped inside an iFrame tag and so it's in its own browser environment and can't get access to the Canvas environment. You could still do annoying things like pop-up messages telling student that their account has been hijacked, but it wouldn't be able to take over and do things as that student within Canvas.
You only mentioned viewing files from the Files page, but I did go ahead and use the Content Selector to add a link to the file inside a page and inside a quiz. The link returns you to the Files page where it is embedded within an iframe and protected from bad scripts.
This discussion post is outdated and has been archived. Please use the Community question forums and official documentation for the most current and accurate information.