JavaScript security or how to write secure JS code. Static type analysis in JavaScript. Trying Facebook's Flow Analyzer Version Control Tools

It is a modular wrapper that generates a dependency graph with all modules for a JavaScript application. Webpack packages modules into one or more small packages for browser loading. In addition, Webpack can be used as a task launcher as it analyzes dependencies between modules and generates resources (assets). You can learn more about using Webpack in your projects in our.

  • Grunt is a task runner designed to automate repetitive and time-consuming tasks. Its software ecosystem has a huge number of plugins (over 6000).
  • Gulp is not just another task manager, but a tool with an interesting approach: it defines tasks in JavaScript as functions, also the GUl automates painful tasks, offering an extensive software ecosystem (over 2,700 plugins), and it also provides better transparency and control over the process.
  • Browserify allows software developers to use NodeJS style modules in browsers. You define the dependencies, and Broweserify packs it all into a neat JS file.
  • Brunch.io is a tool that focuses on speed and simplicity. It comes with simple configuration and detailed documentation to get you started quickly. Brunch automatically generates a map of JS files along with CSS stylesheets, making it easy to debug on the client side.
  • Yeoman is a versatile tool that can be used with almost any programming language (JavaScript, Python, C #, Java, and others). This basic code generation system with a rich software ecosystem (over 6200 plugins) is used to develop web applications. With Yeoman, you can quickly create new projects without forgetting to maintain and improve existing ones.
  • IDE and code editors

    • Swagger is a set of rules and tools for describing APIs. The tool is a language-independent utility. This means that Swagger creates clear documentation that is readable by both humans and machines, allowing you to automate API-dependent processes.
    • JSDoc is a set of tools that automatically generates multipage text documentation (HTML, JSON, XML, etc.) from comments from JavaScript source code. This application can come in handy for managing large-scale projects.
    • jGrouseDoc (jGD) is a flexible open source tool that allows developers to generate APIs from comments from JavaScript source code. jGD documents not only variables and functions, but also namespaces, interfaces, packages and some other elements.
    • YUIDoc is an application written in NodeJS. It uses syntax similar to Javadoc and Doxygen. It also boasts live preview support, extended language support, and advanced markup.
    • Docco is a free documentation tool written in "literary" CoffeeScript. It creates an HTML document to display your comments interspersed with code. It should be noted that the tool supports not only JavaScript, but other languages ​​as well. For example, Python, Ruby, Clojure and others.

    Testing tools

    JavaScript testing tools are designed to detect bugs during development to avoid future user bugs. As the complexity of custom applications grows, automated tests not only improve application performance, but also help companies keep budget.

    • Jasmine is a Behavior-driven Development (BDD) framework for testing JS code. It has no external dependencies and does not require the DOM to run. Jasmine has a clean and straightforward syntax that makes testing faster and easier. Also, the framework can be used to test Python and Ruby code.
    • Mocha is a functional test framework that runs on Node.js in the browser. It runs tests consistently to provide flexible and accurate reporting, making asynchronous tests fun and easy. Mocha is often used in conjunction with Chai to check test results.
    • PhantomJS is often used for front-end tests and unit tests. Considering that this is something like "headless" WebKit, scripts are much faster to execute. It also includes built-in support for various web standards. For example JSON, Canvas, DOM handling, SVG and CSS selectors.
    • Protractor is an end-to-end testing framework written in Node.js for testing AngularJS and Angular applications. It was built on top of WebDriverJS and validates applications like an end user using custom drivers and inline events.

    Debugging tools

    Debugging code is a laborious and time-consuming process for JavaScript developers. Debugging tools are especially useful when dealing with thousands of lines of code. Many of the debugging tools provide fairly accurate results.

    • JavaScript Debugger is a tool from the Mozilla Developer Community (MDN) that can be used as a stand-alone web application to debug code across browsers. Firefox offers local and remote functionality, and the ability to debug code on an Android device using Firefox for Android.
    • Chrome Dev Tools is a set of tools that includes several utilities for debugging JavaScript code, editing CSS, and testing application performance.
    • ng-inspector is a cross-browser extension designed to help developers write, understand and debug AngularJS applications. The utility comes with real-time updates, DOM highlighting, direct access to regions, models and other elements of the application.
    • Augury is an extension for the Google Chrome browser and for debugging Angular 2 applications. It allows Angular 2 application developers to directly analyze application structure and performance, and detect changes.

    Security Tools

    • Snyk is a commercial tool for detecting, fixing and preventing known vulnerabilities in JavaScript, Java and Ruby applications. The service has its own vulnerability database and pulls data from NSP and NIST NVD. The patches and updates offered by the company allow developers to anticipate security risks.
    • The Node Security Project offers useful tools for dependency scanning and vulnerability detection. NSP uses its own database, built on npm module scanning, as well as data from common databases such as the NIST NVD (National Vulnerability Database). In addition, NSP provides integration with GitHub Pull Request and CI software. There is also real-time scanning, warnings and recommendations for eliminating vulnerabilities in Node.js applications.
    • RetireJS is an open source dependency checker. Includes various components such as command line scanner, Grunt plugin, Firefox and Chrome extensions, Burp plugins and OWASP ZAP. Retirejs collects vulnerability information from the NIST NVD and other sources such as bug trackers, blogs, and mailing lists.
    • Gemnasium is a commercial tool with a free trial. It supports a variety of technologies and packages including Ruby, PHP, Bower (JavaScript), Python, and npm (JavaScript). The Gemnasium security tool comes with useful features like automatic updates, real-time alerts, security notifications, and integration with the Slack service.
    • OSSIndex supports various ecosystems (Java, JavaScript and .NET / C #) and many platforms such as NuGet, npm, Bower, Chocolatey, Maven, Composer, Drupal, and MSI. It collects vulnerability information from the National Vulnerability Database (NVD) and reviews. It also processes information from community members.

    Analytics and code optimization tools

    To check the quality of the code, one usually turns to functional testing and unit testing. However, there is another approach that allows developers to check the quality of the code and its compliance with coding standards, namely static code analysis.

    Currently, modern software combines tools for analyzing static code during development in order to exclude low-quality code from entering production.

    • JSLint is a web analytic tool for checking JavaScript code quality. Once it detects a problem at the source, it returns a message with a description of the problem and an approximate location in the code. JSLint is able to parse some style norms and expose syntax errors and structural problems.
    • JSHint is a flexible community-driven tool for detecting bugs and potential problems in your JS code, and JSHint is a fork of JSLint. The main purpose of this static code analysis tool is to help JavaScript developers working on complex programs. It is capable of detecting syntax errors, implicit data type conversions, or missing variable. However, it cannot detect the speed and correctness of your application, nor can it identify memory problems in your application. JSHint is a fork from JSLint.
    • ESLint is an open source linter for JSX and JavaScript web applications. It helps you spot questionable patterns or find code that doesn't match specific styles. This allows developers to detect errors in JS code without executing it, thus saving time. Written in Node.js, the tool offers a responsive runtime and smooth installation via npm.
    • Flow is a static JavaScript code controller developed by Facebook. It uses static type annotations to check your code for errors. Types are parameters set by the developers, and Flow checks your software for compliance.

    Version control tools

    • In recent years, Git has become a widely used version control system for both small and large projects. This free utility provides excellent speed and efficiency. Its popularity is due to its distributed system and different types of controls, as well as a staging area where versions can be previewed and formatted just before the commit is complete.
    • The Subversion tool or SVN has gained immense popularity and is still widely used in open source projects and platforms such as Python Apache or Ruby. This CVS comes with many features to manage various operations (rename, copy, delete, etc.), merges, file locking, and more.

    Package and dependency management tools

    The list of the best JavaScript development tools can go on and on. In this article, you have seen only the popular and reliable tools that serve as the basis for quality products.

    ALEXANDER MAYOROV, programmer, 11 years of experience in programming, seven of which devoted to development for mobile devices

    Static Type Analysis in JavaScript
    Trying Facebook Flow Analyzer

    Facebook has introduced a new open source project Flow - a static code analyzer for the JavaScript language. The main purpose of the analyzer development is to simplify the search for errors.

    In addition, Flow provides a TypeScript-style JavaScript syntactic extension for explicitly specifying types. Many of the new features introduced in the ECMAScript 6 specification are supported.

    The topic of typing in programming languages ​​is often touched upon. This is the subject of holivars and determining the positive or negative trait of a particular language. There has been a lot of talk lately about typing in JavaScript. Someone likes it as it is. People familiar with other programming languages, especially those with strong explicit typing, consider this approach "a grenade in the hands of a monkey." We all know that JavaScript is a loosely dynamically typed language. Front-end development gurus have learned how to use this to their advantage, but the code is sometimes too heavy to understand. Those who just come to the world of JavaScript programming are perplexed by the magic that the interpreter does, and often catch errors out of the blue. But first, let's dig a little bit about typing in general. What is it like?

    Typing in programming languages

    By typing, programming languages ​​are divided into two big camps - typed and untyped. For example, typed languages ​​include C, Python, PHP, Lua, JavaScript. Examples of untyped languages: assembler, Forth, Brainfuck. Yes Yes exactly. JavaScript, like many other interpreted languages, is typed. Therefore, in no case say that it is untyped. Especially in job interviews.

    In turn, typed languages ​​are divided into several overlapping categories:

    • Statically or dynamically typed.
    • Strong or loosely typed.
    • Explicitly or implicitly typed.

    Statically typed languages

    With static typing, the final types of variables and functions are set at compile time. The compiler corrects your type mismatch errors even before the program starts. Examples of languages: C, Java, C #.

    Dynamically typed languages

    In dynamic typing, all types are found out at runtime. And if you make a mistake, you will only know about it when you run the program. Therefore, when dynamically typing, it is very important to pay special attention to checking and catching errors. Examples of languages: JavaScript, PHP, Python, Ruby.

    Strong typing (strong)

    Strongly typed languages ​​do not allow mixing different types in expressions and will not perform automatic implicit conversions. For example, you cannot subtract a number or any other type other than a string from a string. Examples of languages: Java, Python, Haskell, Lisp.

    Lax typing (weak)

    Loosely typed languages ​​perform many implicit conversions automatically. They do this even if loss of precision or conversion may occur, ambiguously. Examples of languages: PHP, JavaScript, Visual Basic.

    Explicit typing

    In explicitly typed languages, the type of new variables / functions and arguments must be specified explicitly. Examples of languages: C ++, D, C #.

    Implicit typing

    In languages ​​with implicit typing, the task of specifying the types is transferred to the compiler / interpreter. Examples of languages: JavaScript, PHP, Lua. In such languages, as a rule, objects have special methods that are called upon casting to a type. For example, PHP has a _toString () method, and JavaScript has a method of the same name, but without an underscore, toString (). These methods are called when casting an object to a string type. Sometimes such methods are called magic (any implicit processes are always magic).

    It is important to note that all of these categories overlap. Based on these categories, we see that JavaScript is dynamically implicitly typed. And if we speak exaggeratedly, then the nature of the language can be described as follows: in any incomprehensible situation, bring everything to primitives, mainly to a line. Although in reality everything is a little more complicated, we will not go into details now.

    "Why do we need typing?" - you may ask. JavaScript has lived well without it for 20 years. The answer is simple: JavaScript has never been used to solve complex enterprise-level problems. Now this language has gone beyond the browser and entered the backend territory. When writing a large application, it becomes difficult to catch errors that are often associated with type casting.

    JavaScript add-ins

    Since JavaScript is executed on the client side (in browsers), one of the options for solving the problem is to create a language - a dialect that will be compiled into JS. He acts as an assembler.

    Languages ​​such as TypeScript, Dart, AtScript have emerged that add static strong typing and even runtime type checking (although this adds overhead). All these languages ​​do not just add types, they also add either syntactic sugar or even their own VM implementation, which is written in JS.

    Read the entire article in the journal "System Administrator", No. 1-2 for 2015 on pages 86-88.

    A PDF version of this issue can be purchased from our store.

    1. The Flow website is http://flowtype.org.

    In contact with

    Developing secure JavaScript applications is a tricky business. But quite doable. In today's article, we will look at the features of JavaScript that cause security problems and talk about how to help avoid them.

    Why Writing Safe JS Code Is Difficult

    So, here are 5 reasons why it is difficult to write safe code in JS

    The compiler won't help

    JavaScript is an interpreted language. This means that the compiler will not complain about something all the time, refusing to work and pushing you to fix bugs and optimize your code.

    Dynamic JavaScript

    JavaScript is dynamic, weakly typed, and asynchronous. And these are all signs that it is easier to get into trouble.

    1. Language tools like eval and including third-party code via script src allows lines to be executed right at runtime. As a consequence, it is difficult to give "static guarantees" that the code will behave in a certain way. This also complicates dynamic analysis (see scientific work).

    Using eval

    2. Weak typing leads to the fact that it is not easy to apply established methods of static analysis - at least in comparison with statically typed languages ​​(for example, Java).

    3. Asynchronous callbacks, which JavaScript allows calls through mechanisms like setTimeout and XMLHttpRequest (the very famous AJAX), statistically hide the most insidious errors.

    Intricate JS Features

    So many things have not been dragged into JavaScript over the years! In particular, it has prototypes, first-class functions, and closures. They make the language even more dynamic and more difficult to write secure code.

    1. Prototypes. Their meaning is that programs are written in the spirit of an object-oriented approach, but without using classes. With this approach, objects inherit the properties they need directly from other objects (prototypes). At the same time, prototypes in JS can be redefined right at runtime. And if this override happens, then the effect immediately spreads to all objects that inherit the properties of the overridden prototype.

    How prototypes are processed

    For the sake of fairness, it must be said that the new ECMAScript specifications also contain classes.

    2. First class functions. JS has a very flexible object and function model. Object properties and their values ​​can be created, changed or deleted right at runtime, and all of them can be accessed through first class functions.

    3. Closures. If you declare a function inside another function, then the first one gets access to the variables and arguments of the last one. Moreover, these variables continue to exist and remain available to the internal function - even after the external function in which these variables are defined has completed.

    Because of this flexibility and dynamism of JavaScript (see points 1 and 3), determining a set of all available object properties in static analysis is an unsolvable task. However, web developers make use of the dynamic features of the language everywhere, and, accordingly, they cannot be neglected when analyzing the code. Otherwise, what is the security guarantee?

    Close interaction between JavaScript and DOM

    This is to provide a seamless web page refresh, right at runtime. The DOM is known to be a platform- and language-neutral standard object model for rendering HTML and XML documents. The DOM has its own API for working with the rendered document: to dynamically access, move and update the rendered document (its content, structure and style). Changes to the DOM can be made dynamically through JavaScript. And these changes are immediately displayed in the browser.

    Thanks to the DOM, web pages loaded into the browser can be updated in stages as data is loaded from the server. However, there is a downside to this convenience: the code snippets that are responsible for dynamic communication between JS and the DOM are especially error-prone.

    The most common errors in web applications

    Complex event interactions

    JavaScript is an event-driven language. It allows developers to register so-called event listeners on DOM nodes. Although most events are triggered by user actions, there are some that can be triggered without it, such as timed events and asynchronous calls. In this case, each event can be echoed throughout the DOM tree and activate several "listeners" at once. Sometimes it is not a trivial task to keep track of all this.

    How events are handled

    For these reasons, JS code can be difficult to understand, analyze, and test. Special utilities will make life easier for a web developer and will help to write safe code.

    JS Code Testing Utilities

    There are utilities for parsing (eg Esprima, Rhino), optimization (eg Google Closure Compiler) and static code analysis for common syntax errors (eg JSHint).

    In addition, there are several proven frameworks that help web developers cover JS code with tests. Among them:

    • QUnit is a popular unit testing framework;
    • Jasmine - Behavior-driven Development (BDD) framework for code testing;
    • Mocha is a code testing framework that runs in both Node.js and the browser.
    • jsTestDriver is a framework that, among other things, can run a suite of tests across multiple browsers at once.

    In addition, there are testing frameworks that emulate browser behavior and allow test cases to run automatically. They are especially useful when debugging the sections of code that are responsible for the interaction between JS and the DOM, and provide a convenient infrastructure for manipulating the DOM.

    For example, Selenium, PhantomJS, and SlimerJS provide an API through which you can launch and work with browser instances. Through the API, you can trigger events and access DOM elements right at runtime - that is, test the code in conditions that are as close to real as possible. Of course, a lot of the work will have to be done manually, but even this is already a good help in testing.

    Utilities for static analysis

    Previously, utilities for identifying problematic sections of code were static analyzers. That is, given all the dynamic quirks of JS, could only provide limited help. However, they can also be useful in analysis. Here are some basic examples.

    WARI is a static analyzer that examines dependencies between JS functions, CSS styles, HTML tags, and images. The purpose of this utility is to find unused resources during static analysis. However, the dynamics of WARI, of course, will not cope.

    JSLint is a static code analysis utility written in JavaScript itself. It checks the code against good practice.

    Google Closure Compiler is a JS optimizer that automatically rewrites code to make it faster and more compact. At the same time, all comments and any unused sections of code fly into the pipe.

    WebScent (see scientific work) is an advanced static analyzer. In his work, he proceeds from the fact that the client JS code (the one that is loaded into the browser) is not stored on the server side as a whole, but is scattered throughout the server code in chunks. The "odor" in these chunks cannot be easily detected until a complete client code is generated from them. WebScent analyzes the client code in order to find problem areas in the server code. At the same time, the work of the WebScent static analyzer is mainly reduced to unraveling mixes of HTML, CSS and JS - in order to detect duplicate code and errors in HTML syntax.

    Dynamic analysis utilities

    JSNose is a utility that combines static and dynamic analysis. It analyzes the code for thirteen anti-patterns. Seven of them (including lazy object and long function) are common to all programming languages, and six others (closure smells, excessive global variables, nested callbacks, and others) are JavaScript-specific.

    DOMPletion is an automated utility that helps a web developer understand code when viewed: explains why DOM structures are present, performs dynamic analysis, and also provides a smart autocomplete for code that interacts with the DOM.

    Clematis is a framework that helps unravel complex event interactions. Clematis captures in detail all the events that are triggered during execution, and visualizes them in the form of an abstract behavioral model, which reflects the temporal and causal relationships between components and events.

    conclusions

    So, it can be difficult to trace what is happening when executing scripts in JS, but armed with the right tools, you can find and rewrite problem areas even in the most confusing code. However, JavaScript does not stand still: new and new opportunities appear in it, now it is often used to write applications (both mobile and desktop), and is also increasingly found on servers (and not only) thanks to Node.js. This means that the art of catching bugs must be taken to a new level.

    Not every line of my code is perfect the first time. Well, in some cases ... Sometimes ... Okay - almost never. The truth is, I spend significantly more time correcting my own stupid mistakes than I would like. This is why I use static analyzers in almost every JavaScript file I write.

    Static analyzers look at your code and find errors in it before you run it. They perform simple checks, such as enforcing syntax checking (for example, tabs instead of spaces) and more global checks, such as checking that functions are not overly complex. Static analyzers also look for bugs that cannot be found during testing, for example, == instead of ===.

    In large projects and when working in large teams, you can use a little help in finding such "simple" bugs, which in fact turn out to be not as simple as they seem.

    JSLint, JSHint and Closure Compiler

    There are three main options for static analyzers for JavaScript: JSLint, JSHint, and Closure Compiler.

    JSLint was the first static analyzer for JavaScript. It can be run on the official site or use one of the add-ons that can be run on local files. JSLint finds many important bugs, but it is very tough. Here's a prime example:

    Var s = "mystring"; for (var i = 0; i< s.length; i++) { console.log(s.charAt(i)); }

    JSLint shows two errors in this code:

    Unexpected "++". Move "var" declarations to the top of the function.

    The first problem is the definition of the i variable in the loop conditions. JSLint also does not accept the ++ operator at the end of the loop definition. He wants the code to look like this:

    Var s = "mystring"; var i; for (i = 0; i< s.length; i = i + 1) { console.log(s.charAt(i)); }

    I appreciate the creators of JSLint, but for me it is overkill. It turned out to be tough for Anton Kovalev too, so he created JSHint.

    JSHint works the same as JSLint, but it is written in addition to Node.js and is therefore more flexible. JSHint includes a large number of options, allowing you to perform custom checks by writing your own report generator.
    You can run JSHint from the website, but in most cases it is better to install JSHint as a local command line tool using Node.js. Once you have installed JSHint, you can run it on your files with a command like this:

    Jshint test.js

    JSHint also includes plugins for popular text editors so you can run it as you write your code.

    CLOSURE COMPILER

    Google's Closure Compiler is a completely different kind of program. As its name suggests, it is not only a test program, but also a compiler. It is written in Java and based on Mozilla's Rhino parser. The Closure Compiler includes a simple mode for doing basic code checking, and more complex modes for doing additional checking and enforcing specific view definitions.

    Closure Compiler reports errors in JavaScript code, but also generates minified versions of JavaScript. The compiler removes whitespace, comments, and unused variables and simplifies long expressions to keep the script as compact as possible.

    Google has made a very basic version of the compiler available on the net, but most likely you will want to download Closure Compiler and run it locally.

    Closure Compiler, after checking the code, outputs a list of files into one minified file. So you can run it by downloading the compiler.jar file.

    Java -jar compiler.jar --js_output_file compress.js --js test1.js --js test2.js

    Choosing the right verification program

    In my projects I combine Closure Compiler and JSHint. Closure Compiler does minification and basic validation, while JSHint does more complex code analysis. These two programs work great together, and each of them covers areas that the other cannot. In addition, I can use the JSHint extension to write custom validators. One generic program I wrote tests certain functions that I don't need, such as calling functions that shouldn't be in my project.

    Now that we've covered a few programs to check, let's break down some of the bad code. Each of these six examples is code not worth writing and situations where code checking programs can save you.

    This article uses JSHint for most of the examples, but the Closure Compiler usually generates similar warnings.

    == or ===?

    JavaScript is a dynamically typed language. You don't need to define types as you write your code, and they exist at startup.

    JavaScript offers two comparison operators for manipulating such dynamic types: == and ===. Let's take a look at this with an example.

    Var n = 123; var s = "123"; if (n == s) (alert ("Variables are equal");) if (n === s) (alert ("Variables are identical");)

    Comparison operator == are the remnants of the C language that JavaScript has its roots in. Its use is almost always a mistake: comparing values ​​separately from types is rarely something that a developer actually wants to do. In fact, the number "one hundred twenty three" is different from the string "one two three". These operators are easy to misspell and even easier to misread. Check this code with JSHint and you will get this:

    Test.js: line 9, col 12, Expected "===" and instead saw "==".

    Undefined Variables and Late Definitions

    Let's start with some simple code:

    Function test () (var myVar = "Hello, World"; console.log (myvar);)

    See the bug? I make this mistake every time. Run this code and you get the error:

    ReferenceError: myvar is not defined

    Let's make the problem a little more complicated:

    Function test () (myVar = "Hello, World"; console.log (myVar);)

    Run this code and you get this:

    Hello, World

    This second example works, but has very unexpected side effects. The rules for defining JavaScript variables and scope are confusing at best. In the first case, JSHint will report the following:

    Test.js: line 3, col 17, "myvar" is not defined.

    In the second case, he will report this:

    Test.js: line 2, col 5, "myVar" is not defined. test.js: line 3, col 17, "myVar" is not defined.

    The first example will help you avoid a runtime error. You don't need to test your application - JSHint will find the error for you. The second example is worse, since you won't find a bug as a result of testing.

    The problem in the second example is insidiously subtle and complex. The variable myVar has now disappeared from its scope and moved up to the global scope. This means that it will exist and have the value Hello, World even after the test function has run. This is called global scope pollution.

    The variable myVar will exist for every other function that is run after the test function. Run the following code after running the test function:

    Console.log ("myVar:" + myVar);

    You will still get Hello, World. The variable myVar will hang throughout your code like a template, which leads to complex bugs that you will look for all night before the release, all because you forgot to write var.

    And a teacher of Netology, wrote a series of articles for the blog about EcmaScript6. In the first part, we will look at examples of dynamic code analysis in EcmaScript using Iroh.js.

    Static and dynamic code analysis

    Code analysis tools are a useful tool for detecting and detecting errors and peculiarities in the work of the code. Code analysis can be static and dynamic. In the first case, the source code is parsed and analyzed without executing it, in the second, the execution takes place in a controlled sandboxing environment that provides meta-information about the elements of the application during its execution.

    conclusions

    Iroh.js is a powerful and functional tool for dynamic code analysis in EcmaScript. This tool can be used both for code analysis, including building a call graph, displaying actual types and values ​​in variables and objects, and for code modification on the fly, including code fixes based on events.

    Dynamic analysis is a rather complex method, but for EcmaScript, given the duck typing, the presence of host objects and native functions that allow you to change the behavior of the code on the fly, this is the only way to analyze and debug the code at runtime. Iroh.js can also use code to create functional tests without having to modify it to export values.

    
    Top