Close Menu
Soshace Digital Blog

    Subscribe to Updates

    Get The Latest News, Updates, And Amazing Offers

    What's Hot
    Events

    Google I/O 2019: New JavaScript Features

    JavaScript

    Create simple POS with React.js, Node.js, and MongoDB #16: Order Screen

    Programming

    3. Уроки Express.js. Шаблонизация с EJS: Layout, Block, Partials

    Important Pages:
    • Home
    • About
    • Services
    • Contact Us
    • Privacy Policy
    • Terms & Conditions
    Facebook X (Twitter) Instagram LinkedIn YouTube
    Today's Picks:
    • Scaling Success: Monitoring Indexation of Programmatic SEO Content
    • Leveraging Influencers: Key Drivers in New Product Launches
    • How Privacy-First Marketing Will Transform the Industry Landscape
    • The Impact of Social Proof on Thought Leadership Marketing
    • Balancing Value-Driven Content and Promotional Messaging Strategies
    • Top Influencer Marketing Platforms to Explore in 2025
    • Emerging Trends in Marketing Automation and AI Tools for 2023
    • Strategies to Mitigate Duplicate Content in Programmatic SEO
    Thursday, September 18
    Facebook X (Twitter) Instagram LinkedIn YouTube
    Soshace Digital Blog
    • Home
    • About
    • Services
    • Contact Us
    • Privacy Policy
    • Terms & Conditions
    Services
    • SaaS & Tech

      Maximizing Efficiency: How SaaS Lowers IT Infrastructure Costs

      August 27, 2025

      Navigating Tomorrow: Innovations Shaping the Future of SaaS

      August 27, 2025

      Maximizing Impact: Strategies for SaaS & Technology Marketing

      August 27, 2025
    • AI & Automation

      Enhancing Customer Feedback Analysis Through AI Innovations

      August 27, 2025

      Navigating the Impact of AI on SEO and Search Rankings

      August 27, 2025

      5 Automation Hacks Every Home Service Business Needs to Know

      May 3, 2025
    • Finance & Fintech

      Critical Missteps in Finance Marketing: What to Avoid

      August 27, 2025

      Analyzing Future Fintech Marketing Trends: Insights Ahead

      August 27, 2025

      Navigating the Complex Landscape of Finance and Fintech Marketing

      August 27, 2025
    • Legal & Compliance

      Exploring Thought Leadership’s Impact on Legal Marketing

      August 27, 2025

      Maximizing LinkedIn: Strategies for Legal and Compliance Marketing

      August 27, 2025

      Why Transparency Matters in Legal Advertising Practices

      August 27, 2025
    • Medical Marketing

      Enhancing Online Reputation Management in Hospitals: A Guide

      August 27, 2025

      Analyzing Emerging Trends in Health and Medical Marketing

      August 27, 2025

      Exploring Innovative Content Ideas for Wellness Blogs and Clinics

      August 27, 2025
    • E-commerce & Retail

      Strategic Seasonal Campaign Concepts for Online and Retail Markets

      August 27, 2025

      Emerging Trends in E-commerce and Retail Marketing Strategies

      August 27, 2025

      Maximizing Revenue: The Advantages of Affiliate Marketing for E-Commerce

      August 27, 2025
    • Influencer & Community

      Leveraging Influencers: Key Drivers in New Product Launches

      August 27, 2025

      Top Influencer Marketing Platforms to Explore in 2025

      August 27, 2025

      Key Strategies for Successful Influencer Partnership Negotiations

      August 27, 2025
    • Content & Leadership

      The Impact of Social Proof on Thought Leadership Marketing

      August 27, 2025

      Balancing Value-Driven Content and Promotional Messaging Strategies

      August 27, 2025

      Analyzing Storytelling’s Impact on Content Marketing Effectiveness

      August 27, 2025
    • SEO & Analytics

      Scaling Success: Monitoring Indexation of Programmatic SEO Content

      August 27, 2025

      Strategies to Mitigate Duplicate Content in Programmatic SEO

      August 27, 2025

      Effective Data Visualization Techniques for SEO Reporting

      August 27, 2025
    • Marketing Trends

      How Privacy-First Marketing Will Transform the Industry Landscape

      August 27, 2025

      Emerging Trends in Marketing Automation and AI Tools for 2023

      August 27, 2025

      Maximizing ROI: Key Trends in Paid Social Advertising

      August 27, 2025
    Soshace Digital Blog
    Blog / Programming / 19. Уроки Node.js. Безопасный Путь к Файлу в fs и path.
    Programming

    19. Уроки Node.js. Безопасный Путь к Файлу в fs и path.

    bragin_paBy bragin_paOctober 19, 2016Updated:December 6, 2024No Comments6 Mins Read
    Facebook Twitter Pinterest Telegram LinkedIn Tumblr Email Reddit
    19. Уроки Node.js. Безопасный Путь к Файлу в fs и path.
    Share
    Facebook Twitter LinkedIn Pinterest Email Copy Link

    fantastic-wooden-pier-frisco-night
    В этой статье мы рассмотрим, как при помощи Node.js создать веб-сервер, который будет возвращать файл пользователю из директории public. Может возникнуть вопрос: зачем здесь Node.js? почему бы не сделать это на другом сервере? Вопрос совершенно уместен. Да, для отдачи файлов, как правило, другие сервера будут более эффективны. С другой стороны, Node.js, во-первых, тоже работает весьма неплохо, а во-вторых, перед отдачей файла может совершить какие-то интеллектуальные действия, например, обратиться к базе данных, проверить, имеет ли пользователь право на доступ к данному файлу, и только если имеет, тогда уже отдавать.

    Пожалуйста загрузите код из нашего репозитория, писать сегодня не придется. Прежде чем начать, разбираться необходимо установить модуль mime:

    npm install mime

    Так выглядит наш server.js:

    var http = require('http');
    var fs = require('fs');
    var url = require('url');
    var path = require('path');
    
    var ROOT = __dirname + "/public";
    
    http.createServer(function(req, res) {
    
        if (!checkAccess(req)) {
            res.statusCode = 403;
            res.end("Tell me the secret to access!");
            return;
        }
    
        sendFileSafe(url.parse(req.url).pathname, res);
    
    }).listen(3000);
    
    function checkAccess(req) {
        return url.parse(req.url, true).query.secret == 'o_O';
    }
    
    function sendFileSafe(filePath, res) {
    
        try {
            filePath = decodeURIComponent(filePath);
        } catch(e) {
            res.statusCode = 400;
            res.end("Bad Request");
            return;
        }
    
        if (~filePath.indexOf('')) {
            res.statusCode = 400;
            res.end("Bad Request");
            return;
        }
        
        filePath = path.normalize(path.join(ROOT, filePath));
    
        if (filePath.indexOf(path.normalize(ROOT)) != 0) {
            res.statusCode = 404;
            res.end("File not found");
            return;
        }
    
        fs.stat(filePath, function(err, stats) {
            if (err || !stats.isFile()) {
                res.statusCode = 404;
                res.end("File not found");
                return;
            }
    
            sendFile(filePath, res);
        });
    }
    
    function sendFile(filePath, res) {
    
        fs.readFile(filePath, function(err, content) {
            if (err) throw err;
    
            var mime = require('mime').lookup(filePath); // npm install mime
            res.setHeader('Content-Type', mime + "; charset=utf-8");
            res.end(content);
        });
    
    }

    http.create здесь очень прост.

    http.createServer(function(req, res) {
    
        if (!checkAccess(req)) {
            res.statusCode = 403;
            res.end("Tell me the secret to access!");
            return;
        }
    
        sendFileSafe(url.parse(req.url).pathname, res);
    
    }).listen(3000);

    Он будет проверять, есть ли доступ к данному файлу, и если есть, то уже отдавать. Для проверки доступа мы будем использовать следующую функцию (которая является по своей сути является Fake function), которая будет выполнять url parse , и если есть параметр secret, который будет равен ‘o_O’, то считается, что доступ есть:

    function checkAccess(req) {  
      return url.parse(req.url, true).query.secret == 'o_O';  
    } 
    

    В реальной жизни такая проверка, конечно же, будет производиться при помощи cookies, базы данных и т.д.
    Основная функция, которая нас интересует, это sendFileSafe:

    sendFileSafe(url.parse(req.url).pathname, res);
    

    Именно эта функция должна, получив путь от user, отослать соответствующий файл с директории public, учитывая путь директории. Важнейший аспект, который в ней должен быть заложен, это безопасность. Какой бы путь не передал пользователь, он ни в коем случае не должен получить файл вне директории public. Например, обращение:

    Read More:  Уроки React. Урок 6.

    http://localhost:3000/index.html?secret=o_O

    должно возвращать файл index.html,  картинка здесь взята из директории

    <img src ="deep/nodejs.jpg?secret=o_O">

    А если бы мы не указали secret:

    http://localhost:3000/index.html

    то оно должно было бы выдать ошибку с кодом 403.

    А если бы я попробовали бы указать вот так:

    http://localhost:3000/server.js

    то тоже была бы ошибка. И так для любых попыток выйти за пределы этой директории.

    Итак, смотрим функцию sendFileSafe, чтобы получить пример безопасной работы с путем от посетителя. Эта функция состоит из нескольких шагов.

    function sendFileSafe(filePath, res) {
    
        try {
            filePath = decodeURIComponent(filePath);
        } catch(e) {
            res.statusCode = 400;
            res.end("Bad Request");
            return;
        }

    На первом шаге мы пропускаем путь через decodeURIComponent, ведь по стандарту “http” многие символы кодируются. Получив такой “url”, мы обязаны его декодировать обратно, при помощи вот такого вызова:

    decodeURIComponent

    При этом, если “url” закодирован заведомо неверно, то возникнет ошибка, которую необходимо поймать и обработать. Код 400 как раз означает, что “url” некорректен и запрос неверен. Можно, конечно, вернуть и 404.
    Когда мы раскодировали запрос, время его проверить. Есть специальный нулевой байт, который в строке “url” присутствовать не должен:

    if (~filePath.indexOf('')) {  
      res.statusCode = 400;  
      res.end("Bad Request");  
      return;  
    }  
    

    Если он есть, то это означает, что кто-то его злонамеренно передал, потому что некоторые встроенные функции Node.js будут работать таким байтом некорректно. Соответственно, если такой байт есть, то мы тоже возвращаем «Bad Request», запрос некорректен.

    Теперь настало время получить полный путь к файлу на диске. Для этого мы будем использовать модуль path.

    filePath = path.normalize(path.join(ROOT, filePath));
    

    Этот встроенный модуль содержит набор самых разных функций для работы с путями. Например, join объединяет пути, normalize – удаляет из пути всякие странные вещи типа “.”, “:”, “//” и  т.д., то есть, делает путь более корректным. Если “url”, который передал пользователь, выглядел так:

    //  /deep/nodejs.jpg

    то после join с ROOT, который представляет собой вот эту директорию:

    var ROOT = __dirname + "/public";

    он будет выглядеть уже по-другому, например:

    //  /deep/nodejs.jpg ->  /Users/learn/node/path/public/deep/nodejs.jpg  
    

    Наша следующая задача – это убедиться, что этот путь действительно находится внутри директории public. Сейчас, когда у нас уже есть абсолютно точный, корректный путь, это сделать очень просто. Достаточно всего лишь проверить, что вначале находится вот такой префикс:

    Users/learn/node/path/public
    

    то есть, что путь начинается с ROOT. Проверяем. Если это не так, то “File not Found”:

    filePath = path.normalize(path.join(ROOT, filePath));
    
        if (filePath.indexOf(path.normalize(ROOT)) != 0) {
            res.statusCode = 404;
            res.end("File not found");
            return;
        }

    Если путь разрешен, то проверим, что по нему находиться. Если ничего нет, то fs.stat вернет ошибку err:

    fs.stat(filePath, function(err, stats) {  
      if (err || !stats.isFile()) {  
        res.statusCode = 404;  
        res.end("File not found");  
        return;  
      }  
    

    Если даже ошибки нет, то нужно проверить, файл ли это. В том случае, если это не файл, то это ошибка. Ну а если файл, то все проверено, и надо его отослать. Это делает вложенный вызов sendFile:

    sendFile(filePath, res);  
      });  
    }  
    

    sendFile – функция которая есть в этом же файле, но немного ниже:

    function sendFile(filePath, res) {
    
        fs.readFile(filePath, function(err, content) {
            if (err) throw err;
    
            var mime = require('mime').lookup(filePath); // npm install mime
            res.setHeader('Content-Type', mime + "; charset=utf-8");
            res.end(content);
        });
    
    }

    Она для чтения файла использует вызов fs.readFile, и когда он будет прочитан, то выводит его через res.end:

    res.end(content);

    Обращаем ваше внимание вот на что:  ошибка в этом callback очень маловероятна

    if (err) throw err;

    хотя бы потому, что мы уже проверили, файл есть, это действительно файл и его можно отдать. Но, тем не менее, мало ли что. Например, может возникнуть ошибка при чтении с диска. Так или иначе как-то обработать ошибку надо. Далее, мало просто считать содержимое файла и отправить его, ведь различные файлы должны снабжаться различными заголовками “Content-Tyрe”.

    Read More:  Оценка задачи

    Например, HTML  файл должен иметь тип text/html, файл с картинкой JPEG – image/jpeg и т.д. Нужный тип файла определяется по расширению с использованием модуля ‘mime’.

     var mime = require('mime').lookup(filePath); // npm install

    Для того чтобы все работало, не забудьте его установить. И, наконец, последнее, эта статья была сосредоточена, в первую очередь, на том, чтобы корректно работать с path от посетителя, чтобы сделать все необходимые проверки, декодирование и т.д. Все это очень важно, но что касается отдачи файла, то этот код неверен:

    function sendFile(filePath, res) {
    
        fs.readFile(filePath, function(err, content) {
            if (err) throw err;
    
            var mime = require('mime').lookup(filePath); // npm install mime
            res.setHeader('Content-Type', mime + "; charset=utf-8");
            res.end(content);
        });
    
    }

    потому что readFile полностью просчитывает файл, потом отсылает его в content. А представьте, что будет, если файл очень большой. А если он превышает количество свободной памяти? Тогда вообще все упадет! Поэтому, для того чтобы отсылать файл, нужно либо дать команду специализированному серверу, либо использовать потоки, которые мы рассмотрим в следующей статье.

    tumblr_nvdx0jpq7F1rf2fjgo1_1280
    Материалы для статьи взяты из следующего скринкаста.

    We are looking forward to meeting you on our website blog.soshace.com

    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
    bragin_pa

      Related Posts

      3. Уроки Express.js. Шаблонизация с EJS: Layout, Block, Partials

      December 16, 2016

      Уроки Express.js . Логгер, Конфигурация, Шаблонизация с EJS. Часть 2.

      December 2, 2016

      2. Уроки Express.js . Логгер, Конфигурация, Шаблонизация с EJS. Часть 1.

      November 24, 2016
      Leave A Reply Cancel Reply

      You must be logged in to post a comment.

      Stay In Touch
      • Facebook
      • Twitter
      • Pinterest
      • Instagram
      • YouTube
      • Vimeo
      Don't Miss
      JavaScript May 26, 2023

      Working with Jotai as your next state management in React

      Despite being efficient and scalable, most common state management needed additional boilerplate code on setup. As a developer who is continually looking for efficient and user-friendly options, I came across Jotai, a minimalistic state management tool that can be used in constructing scalable react applications. In this tutorial, I will walk you through the Jotai library as well as teach you how to utilize Jotai to build a simple application.

      Strategies to Boost B2B Lead Conversion Rates Effectively

      December 17, 2024

      Overview of Bots in Social Media and Messengers

      August 30, 2019

      Mastering the Interview Process for Management Roles

      December 7, 2024

      Categories

      • AI & Automation
      • Angular
      • ASP.NET
      • AWS
      • B2B Leads
      • Beginners
      • Blogs
      • Business Growth
      • Case Studies
      • Comics
      • Consultation
      • Content & Leadership
      • CSS
      • Development
      • Django
      • E-commerce & Retail
      • Entrepreneurs
      • Entrepreneurship
      • Events
      • Express.js
      • Facebook Ads
      • Finance & Fintech
      • Flask
      • Flutter
      • Franchising
      • Funnel Strategy
      • Git
      • GraphQL
      • Home Services Marketing
      • Influencer & Community
      • Interview
      • Java
      • Java Spring
      • JavaScript
      • Job
      • Laravel
      • Lead Generation
      • Legal & Compliance
      • LinkedIn
      • Machine Learning
      • Marketing Trends
      • Medical Marketing
      • MSP Lead Generation
      • MSP Marketing
      • NestJS
      • Next.js
      • Node.js
      • Node.js Lessons
      • Paid Advertising
      • PHP
      • Podcasts
      • POS Tutorial
      • Programming
      • Programming
      • Python
      • React
      • React Lessons
      • React Native
      • React Native Lessons
      • Recruitment
      • Remote Job
      • SaaS & Tech
      • SEO & Analytics
      • Soshace
      • Startups
      • Swarm Intelligence
      • Tips
      • Trends
      • Vue
      • Wiki
      • WordPress
      Top Posts

      Introduction to Web Components. Part 1: Native vs Virtual DOM

      JavaScript December 13, 2019

      Daily Schedule Post

      JavaScript June 25, 2016

      Profiling Tools and Techniques for Node.js Applications

      Express.js February 6, 2024

      Strategies for Overcoming Recruitment Challenges in 2023

      Recruitment December 4, 2024

      Subscribe to Updates

      Get The Latest News, Updates, And Amazing Offers

      About Us
      About Us

      Soshace Digital delivers comprehensive web design and development solutions tailored to your business objectives. Your website will be meticulously designed and developed by our team of seasoned professionals, who combine creative expertise with technical excellence to transform your vision into a high-impact, user-centric digital experience that elevates your brand and drives measurable results.

      7901 4th St N, Suite 28690
      Saint Petersburg, FL 33702-4305
      Phone: 1(877)SOSHACE

      Facebook X (Twitter) Instagram Pinterest YouTube LinkedIn
      Our Picks
      React Native

      Building a Realtime Messaging app with React Native and Firebase

      JavaScript

      Visualizing Logs from a Dockerized Node Application Using the Elastic Stack

      Programming

      Effective Techniques for Utilizing Databases in Programming

      Most Popular

      SMART Financial Goals for Remote Workers

      Remote Job

      Уроки React. Урок 3

      Programming

      Setting CSS Styles with JavaScript

      CSS
      © 2025 Soshace Digital.
      • Home
      • About
      • Services
      • Contact Us
      • Privacy Policy
      • Terms & Conditions

      Type above and press Enter to search. Press Esc to cancel.