Computers Windows Internet

JavaScript security or how to write secure JS code. Version control tools

ALEXANDER MAYOROV, programmer, 11 years of experience in programming, seven of which he 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 JavaScript. 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 traits 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 such languages ​​as 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 of 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 an object is cast 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 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. It 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

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 the 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 that take a lot of time. 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 for developing 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 multi-page 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 catch 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. The framework can also 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 working 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 standalone 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 a variety of 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, thereby 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 various 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.

    And a teacher of Netology, wrote a series of articles for the blog about EcmaScript6. In the first part, we will look at the 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, which 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.

    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 JSHint installed, 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.


    The 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 validators 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 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.


    This entry passed through the Full-Text RSS service - if this is your content and you "re reading it on someone else" s site, please read the FAQ at http://ift.tt/jcXqJW.


    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 JSHint installed, 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.

    The 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 validators 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 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.