Author: Alexander

  • Strengthening brute force protection

    We added the new logic to prevent brute force attacks. Service will check your log in status once per hour and if some IP’s have 10 and more attempts to log in, then these IP’s will be banned for next 24 hours.

    It makes the brute force protection tougher and doesn’t waste the server’s resources on these IP’s.

    Download Security & Firewall by CleanTalk.

  • Compass Pool Centre Newcastle New Website Project 2016

    Old Website Needing to Be Rebuilt

    Compass Pool Centre Newcastle is an authorised Compass Pools Australia dealership based in Newcastle. We deliver high quality fibreglass swimming pools throughout the Newcastle and Hunter region in NSW, Australia. Thanks to hundreds of satisfied customers, we have had a lot of new leads each month. However, to reach more people interested in buying a swimming pool, we needed to improve our online presence.

    The old website was being used for several years and was not really updated. Thus, some of the information were outdated and other missing. The website did not feature enough content and because of this, we could not aim at higher positions in search engines’ search results pages. It needed a visual redesign, structural change, and technical modernisation to keep pace with current website development trends and industry best-practices.

    New Project Starting in April 2016

    In April 2016, the new website project started. Catnapweb.com.au was selected as the contractor for developing the new website. They have worked with Compass Pools Australia on several projects since December 2015 and thanks to this, they knew the environment and Compass products well and could build the new website including content and optimisation for search engines.

    In May 2016, the new website was launched on the compassnewcastle.com.au domain. It featured a completely new design, a lot of fresh content, and it was optimised for mobile devices and search engines. Within the new website, a lot of content is dedicated to precisely describe pool shapes and parameters unique to Compass pools, technologies that help customers enjoy Compass pool without the need of everyday care and show pool installation pictures as the inspiration for new customers. There are numerous unique features on the website. For example, each pool shape can be rotated in 3D by the website visitor, thus enabling exploring the pool from all sides. The shape page also features description of the shape, table with available sizes and nice photo gallery with selected installations of the pool shape.

    Unique Content on the Website

    The website features a lot of new content including secret weapons distinguishing Compass from other pool manufacturers and Advice section with useful information for all prospective and current pool owners. One of the innovations that were implemented on this website, is a set of Call to Actions. Except of the standard contact form, another chances to interact with the company were created and offered to website visitors. One of them is the page introducing printed version of Pool Magazine. This magazine was created by Compass Pools Australia as a comprehensive material containing the best information about pool ownership. The Pool Buyers Guide, as we call the magazine, has 70 pages full of information on selecting the right pool, costs to buy a pool, pool ownership costs and much more. It has been a great success to get in touch with people through this offer. Because the magazine is sent to everyone for free, many people have requested it since the launch of the new website.

    Also, another new service was added to the website. In 2016, Compass Pools Australia have introduced a new range of complementary products. These can be added to a standard fibreglass swimming pool to create unique, customised fibreglass pools. This concept has been named Customise your pool and we introduced it to the website visitors on a separate page. Here, they can find information about Maxi Rib technology, beach zones, grand entry benches, pool and spa water combos, and various water features.

    Technical Solution

    The new website runs on WordPress, currently the 4.7 version. It is built using The7 universal theme that has probably the most features on today’s theme market and is very flexible and versatile. There were several challenges we needed to go conquer when building the website. One of them was selecting the best solution for generating the 3D rotations. We already had 3D models of all our pools ready, now we needed to add surface material to it and export it to an image sequence usable for 3D rotation. We have spent hours and hours testing different number of pictures in the export, their quality and resolution and dozens of WordPress plugins. Finally, we have found out that the only suitable solution for us is the Smart Product Viewer plugin. We have found a balance between the usability of the rotation and the performance of the website. To optimise the user experience, we did not replace the static 3D pool shape representation located on top of the page, but added the interactive pool rotation to the bottom. With this solution in place, user coming to the website does not need to wait until the rotation is loaded and by the time he comes to this part, it is ready for interaction.

    The website contains several forms that collect information from website visitors. They are built with the use of Gravity Forms and stored in the database. Soon after the launch we realised that we are getting spam request sent through the forms. We discussed possible solutions and wanted to implement captcha to stop spam robots filling in the form details. However, Andrej from Catnapweb.com.au came with a suggestion to use CleanTalk, which was already tested on several other websites by him. This solution, despite being quite new, has many advantages over traditional protection. The main is that it does not require and action from the website user and thus, it does not decrease the conversion rate. After setting it up, we have monitored the weekly reports from CleanTalk to determine, if any real requests were not blocked. After several months of running CleanTalk we can happily confirm that the flasepositive rate is 0 and no real request was blocked by CleanTalk. It is very impressive and everyone is happy with this service.

    After 7 months running, we can see the website has started generating a lot of relevant requests. We have the chance to get in touch with people needing more information about swimming pools and we are happy to assist them in their purchasing a pool decision making process.

  • 29 Steps to audit your Website with your own hands and Top 7 Useful Website Audit Tools

    29 Steps to audit your Website with your own hands and Top 7 Useful Website Audit Tools

    Recently significantly expanded the list of aspects that must be considered when analyzing the quality of the site. First of all, this: mobile website optimization; regional resource optimization; the speed of loading pages and other components.

    We have tried to collect in the article the factors that you can directly affect your website and have not considered external factors such as receiving and quality of backlinks, guest posts, and promotion articles.

    For whom this article:

    • for web designers and developers who want to create sites that are originally optimized for SEO,
    • for owners of Internet resources, who want to understand by yourself SEO to increase search traffic.

    Well-structured check-list will allow producing a thorough website audit and finding out what specific factors are negatively affecting performance, and get technical recommendations that should be applied in further work on the resource.

    SEO audit

    1. Duplicates of pages (carefully look for different ways all the duplicates and work with them using the redirect and closing in robots.txt and using the attribute rel=”canonical”). Possible duplicates – http://www.site.ru/index.php (index.html, default.asp), closing slashes, pagination pages, the session variables in the url, search filters, tags of context and other advertising, etc. Other options for the duplicates: http:// and https://, /cat/dir/ and /dir/cat/, site.com and test.site.com, /session_id=123 and so on.
    1. Check for blank pages (which do not contain content). Blank pages can be:
    • removed,
    • closed from indexing (in file robots.txt, see below),
    • filled with content.
    1. “Endless pages” means such pages, where you can set the parameters to some other number and they will allow you to create an infinite number of duplicates for any page (this is often happen in calendars, pagination, products, etc.)
    1. Robots.txt (in Robots spelled out host, sitemap, closed all the service sections, pages to print, admin panel, test domains, URLs of pages from a previous website management system, etc.). Often, also recommend closing: the user profiles, page of creation new topic on forum, login page, personal account, personal messages page, search result page, shopping cart of online store.
    1. Check for redirects on the website (if there are superfluous that need to be removed). Types of redirects:
    • 301 — requested document permanently moved to new URL
    • 302 — the requested documents are temporarily available at another URL.
    1. Sitemap XML. In sitemap no service page and banned by the file robots and meta-tag robots.
    1. Is specified encoding in the code.
    1. Check the presence and the uniqueness of the tags title, description, keywords on every page (all these elements must be different for each page). Are there any missing Titles, meta description, keywords. How much Titles and Description are attractive for clicks.
    1. Try to add the title tag all the keywords, most popular keyword should be closer to the beginning of the tag.
    1. Use the symbol “|” to separate the different phrases in the tag title (for example, name of the page and site).
    1. The tag description does not affect the ranking of a website directly, but search engines may use the content for the snippet of a website in the results. The description length can be from 100 to 250 characters, ideally 155 characters. It is usually one or two meaningful sentences to describe the page, including search queries.
    1. Analysis optimized images on the website. To learn about how to optimize images, it is possible in the help section of Google.
    1. Failure rate (viewing one page), in which pages are many failures, make a list, fill them better.
    1. What are the main points of entry and exit of the site (better to study the content and usability of the main entry points, to analyze where and why they go).
    1. How many pages the average user views (maybe add interesting blocks on the page, “see also”, etc.).
    1. Add the favicon of the site.
    1. Styles and scripts should be loaded in head as separate files.
    1. The page can have only one header h1. The h1 heading should not copy title. Title was created to describe the page, not part of the content of the page. H1 describes the whole page, but h1 only certain content. They carry different meaning, which may coincide.
    1. The attributes alt and title for images should be different. Alt is alternative text for the image if it is not loaded. Title is the title of the picture that POPs up when you hover over the picture and goes in search.
    1. Use HTTPS. Google representatives say that the transition of the site on the HTTPS Protocol – with the addition of 2048-bit SSL key – improve your position on the results pages of the search. Google advises web developers to test their sites with HTTPS using the Qualys Lab tool.

    Technical audit of the website

    1. Check the speed of website loading. This is one of the important factors that affect the ranking of a website in search engines. You can check using Google PageSpeed or Google Search Console.

    To check what items take the longest to load and to consider options for optimization.

    https://tools.pingdom.com/
    https://gtmetrix.com/

    1. Check your website on mobile devices. This can be done in Google Search Console.
    1. The presence of errors in Google Search Console->Crawl->Crawl Errors.
    1. For some sites it makes sense to check the load testing by service http://loadimpact.com/ (free test the behavior of the hosting and the site load up to 50 visitors at a time).
    1. Using the Gzip Test tool, make sure that gzip compression on the server for the website is included.
    1. Check the website for viruses:
    • Norton Safe Web, from Symantec– So, how can you find out if a Web site is a safety risk before you visit it? Norton Safe Web is a new reputation service from Symantec. Our servers analyze Web sites to see how they will affect you and your computer.
    • AVG Online Web Page Scanner – lets you check the safety of individual web pages you are about to visit. LinkScanner will examine the web page in real time to see whether it’s hiding any suspicious downloads.
    1. Checks your web pages for broken links.
      https://validator.w3.org/checklink
      http://www.siteliner.com/ – Find duplicate content, broken links, and more. The free scan is limited to 250 pages.
    1. Checks your Cascading Style Sheets (CSS).
      http://jigsaw.w3.org/css-validator/
    2. Checks HTML for errors or warnings
      https://validator.w3.org/nu/
      http://htmlhelp.com/tools/validator/

    Powerful Website Audit Tools You Should Check

    SEO Site Checkup
    SEO Site Checkup is a free analysis tool that audits the entire website with 45 checks in 6 different categories (common SEO issues, server&security, mobile usability, social media and semantic web). With due consideration of these results, the tool shows up a general score and a number of failed checks.

    Seoptimer
    Seoptimer is a free auditing tool that helps you instantly report critical errors on your website in seconds and recommend what you should do to improve your search rankings.

    SiteAnalyzer
    The tool tests your website’s effectiveness based on 50 parameters, instantly identifies problem areas to fix and shows up all SEO technical mistakes.

    SE Ranking Website Audit
    Not for only identifying website errors at a glance, but also for preparing a list of tasks for website developers, content writers and web designers to prevent from technical issues. It crawls your entire website based on over 70 parameters such as Domain overview, Pages, Meta, Content, Images and Links Analysis, Mobile Optimization, Usability and Technologies.

    Моz Crawl Test
    Moz runs its own site crawler that helps webmasters to check out critical issues, HTTP status codes and other useful data. It also figures out duplicate content, errors in the title tag, server redirects and many other factors that can affect website crawlability.

    SimilarWeb
    With its platform called SimilarWeb, the company uses big data technology for the collection, measurement, analysis and provision data on behavioral patterns and statistics of user engagement of websites and mobile applications. A similar tool Alexa collects statistics from users who have installed a special toolbar. In the case SimilarWeb data comes from their own crawler + data from millions of users with a special toolbar. Is possible to know the list of websites that your visitors have visited with your site. This will allow you to learn more about the interests of the audience and be one step ahead of competitors.

    About the CleanTalk service

    CleanTalk is a cloud service to protect websites from spambots. CleanTalk uses protection methods that are invisible to the visitors of the website. This allows you to abandon the methods of protection that require the user to prove that he is a human (captcha, question-answer etc.).

  • Feature update for spam comment management in WordPress

    Feature update for spam comment management in WordPress

    We launched the update for possibilities to manage spam comments.

    The new option “Smart spam comments filter” divides all spam comments into Automated Spam or Manual Spam.

    For each comment, the service calculates probability — was this spam comment sent automatically or was it sent by a human.

    All automatic spam comments will be deleted permanently without going to the WordPress backend except for comments with Stop-Words. Stop-Word comments will be always stored in the “Pending” folder. Both blocked and banned comments can be seen in the Anti-Spam Log.

    To manage the actions with spam comments, go to the Control Panel, select the website you want to change the actions for and go to “Settings” under the name of the website. On the website settings page, select the desirable item from the “SPAM comment action” menu and click “Save” button at the bottom of the page.

  • The difference between nginx and apache with examples

    The difference between nginx and apache with examples

    During interviews for the role, Linux/Unix administrator in many IT companies ask, what is load average, than Nginx is different from apache httpd, and what is a fork. In this article, I will try to explain what expect to hear in response to these questions, and why.

    It is important to understand very well the basics of administration. In an ideal situation, when setting the system administrator tasks put a number of requirements. If the situation is not ideal, it is, in fact, the requirement for the administrator one: “I want to get everything working”. In other words, the service must be available 24/7 and if a decision does not meet these requirements (scalability and fault tolerance are available), we can say that the administrator did the job badly. But if the different solutions of two administrators work 24/7, how to understand which one is better?

    A good system administrator when selecting solution under given requirements focuses on two conditions: minimum consumption of resources and their balanced distribution.

    Option, when for the one expert is needed 10 servers for the job, and for the second expert only 2, we won’t be discussing that here is better – it is obvious. Further, under resources, I understand CPU, RAM and disk drive (HDD).

    Let us consider the situation: one administrator has created a solution which requires 10% CPU, 5% ram and 10% hdd with all your equipment, and the second used 1% CPU, 40% ram, and 20% hdd. Which of these solutions is better? Here everything is not so obvious. Therefore, a good administrator should always be able to competently find a solution on the basis of available resources.

    Imagine that we’re entry-level programmers, and we are asked to write a basic program for working with the network. The requirements are simple: you have to handle two connections simultaneously by protocol TCP and record what we have adopted in a file.

    Before developing an application, you have to remember which tools offered by the Linux operating system (referred to in the article for all the examples only on the basis of this OS). In Linux we have a set of system calls (i.e., functions in the OS kernel, which we can call directly from our program, thereby forcibly giving CPU time to the kernel):

    1. socket — allocates space in the buffer of the OS kernel to fit our socket. The address of the allocated space is returned from the function in the program;
    2. bind — allows to change the information in the structure of the socket, which OS Linux has allocated for us on command socket;
    3. listen – as well as bind changes data in our structure, allowing you to specify the OS that we want to accept connections on this socket;
    4. connect – tells our OS that it needs to connect to another remote socket;
    5. accept – tells our OS that we want to take a new connection from another socket;
    6. read – we ask the OS to give us from its buffer a certain number of bytes, which it received from the remote socket;
    7. write – we ask the OS to send a certain number of bytes to the remote socket.

    In order to establish a connection, we need to create a socket in the Linux memory l, write it in required data and to connect to the remote side.

    socket → bind → connect → read/write

    But if you trust the OS to make the selection of an outbound port for you (as well as the IP address), then bind won’t be necessary:

    socket → connect → read/write

    In order to receive incoming messages, we need to do:

    socket → bind → listen → accept → read/write

    We now know enough to write a program. Proceed directly to writing, using C. Why C? Because of the language of commands with the same name as system calls (with a few exceptions, like a fork).

    The program differ1.c

    
    // The port on which we listen
    
    #define PORT_NO 2222
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <netinet/in.h>
    
    int main(int argc, char *argv[])
    {
    // The buffer where we will read data from a socket
    long buffersize=50;
    int sockfd, newsockfd;
    socklen_t clilen;
    // The variable in which to store the address of our buffer
    char *buffer;
    struct sockaddr_in serv_addr, cli_addr;
    FILE * resultfile;
    // allocated memory
    buffer = malloc (buffersize+1);
    // open the file for writing our messages        
    resultfile = fopen("/tmp/nginx_vs_apache.log","a");
    bzero((char *) &serv_addr, sizeof(serv_addr));
    bzero(buffer,buffersize+1);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(PORT_NO);
    // create a structure (a socket), here SOCK_STREAM it is tcp/ip socket.
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) error("ERROR opening socket");
    // define the structure of the socket, we will listen on port 2222 on all ip addresses
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error("ERROR on binding");
    // say our OS to accept incoming connections to our socket, maximum 50
    listen(sockfd,50);
    while (1) {
    // in a closed loop process the incoming connection and read from them
    newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
    if (newsockfd < 0) error("ERROR on accept");
    read(newsockfd,buffer,buffersize);
    fprintf(resultfile, buffer);
    fflush (resultfile);
    
    }
    close(sockfd);
    return 0;
    
    }
    

    Compile and run our daemon:

    
    [tolik@ localhost]$
    [tolik@localhost]$ ./differ
    

    Look what happened:

    
    [root@ localhost]# ps axuf | grep [d]iffer
    tolik      45409  0.0  0.0   4060   460 pts/12   S+   01:14   0:00  |   \_ ./differ
    [root@localhost ]# netstat -tlnp | grep 2222
    tcp        0      0 0.0.0.0:2222                0.0.0.0:*                   LISTEN      45409/./differ
    [root@localhost ]# ls -lh /proc/45409/fd
    итого 0
    lrwx------ 1 tolik tolik 64 Апр 19 01:16 0 -> /dev/pts/12
    lrwx------ 1 tolik tolik 64 Апр 19 01:16 1 -> /dev/pts/12
    lrwx------ 1 tolik tolik 64 Апр 19 01:16 2 -> /dev/pts/12
    l-wx------ 1 tolik tolik 64 Апр 19 01:16 3 -> /tmp/nginx_vs_apache.log
    lrwx------ 1 tolik tolik 64 Апр 19 01:16 4 -> socket:[42663416]
    [root@localhost ]# netstat -apeen | grep 42663416
    tcp        0      0 0.0.0.0:2222                0.0.0.0:*                   LISTEN      500        42663416   45409/./differ
    [root@localhost ]# strace -p 45409
    Process 45409 attached - interrupt to quit
    accept(4, ^C 
    Process 45409 detached
    [root@localhost ]#
    

    The process is in state sleep (S+ in the ps command).
    This program will continue to execute (get the CPU time) only when a new connection on the port 2222. In all other cases, the program will never get CPU time: it will not even demand it from the OS and therefore will not affect the load avarage (hereafter LA), consuming only a memory.
    On the other console, run the first client:

    
    [tolik@localhost ]$ telnet localhost 2222
    Connected to localhost.
    Escape character is '^]'.
    test client 1
    Look at the file:
    [root@localhost ]# cat /tmp/nginx_vs_apache.log
    test client 1
    Open a second connection:
    [tolik@localhost ]$ telnet localhost 2222
    Connected to localhost.
    Escape character is '^]'.
    test client 2
    

    We see the result:

    
    [root@localhost ]# cat /tmp/nginx_vs_apache.log
    test client 1
    

    The content of the file shows that only the first message has come from the first client. But the second message we have already sent, and it is somewhere. The OS provides all network connections, and then the message test client 2 is now in the buffer of the operating system memory, which is not available to us. The only way to get this data is to process a new connection by command accept, and then call read.

    Let’s try to write something in the first client:

    
    [tolik@localhost ]$ telnet localhost 2222
    Connected to localhost.
    Escape character is '^]'.
    test client 1
    blablabla
    Check the log:
    [root@localhost ]# cat /tmp/nginx_vs_apache.log
    test client 1
    

    New message has not got to the log. This is due to the fact that we call the read command only once, therefore, the log gets only the first message.

    Let’s try to close our first connection:

    
    [tolik@localhost ]$ telnet localhost 2222
    Connected to localhost.
    Escape character is '^]'.
    test client 1
    bla bla bla
    ^]
    telnet> quit
    Connection closed.
    

    At this point, our program runs on the cycle next read and accept, therefore, receives the message from the second connection:

    
    [root@localhost ]# cat /tmp/nginx_vs_apache.log
    test client 1
    test client 2
    

    Our message bla bla bla never appeared, we’d already closed the socket, and the OS has cleared the buffer, thereby removing our data. We need to upgrade the program to read from a socket as long as the information comes out.

    Program with an infinite read from socket differ2.c

    
    #define PORT_NO 2222
    
    #include <stdio.h>
    #include <string.h>
    #include <netinet/in.h>
    int main(int argc, char *argv[])
    {
            int sockfd, newsockfd;
            socklen_t clilen;
            char buffer;
            char * pointbuffer = &buffer;
            struct sockaddr_in serv_addr, cli_addr;
            FILE * resultfile;
            resultfile = fopen("/tmp/nginx_vs_apache.log","a");
            bzero((char *) &serv_addr, sizeof(serv_addr));
            serv_addr.sin_family = AF_INET;
            serv_addr.sin_addr.s_addr = INADDR_ANY;
            serv_addr.sin_port = htons(PORT_NO);
            sockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (sockfd < 0) error("ERROR opening socket");
            if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error("ERROR on binding");
            listen(sockfd,50);
            while (1) {
                    newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
                    if (newsockfd < 0) error("ERROR on accept");
                    while (read(newsockfd, pointbuffer,1)) {
                                    fprintf(resultfile, pointbuffer);
                                    fflush (resultfile);
                    }
            }
            close(sockfd);
            return 0;
    }
    

    The program is not much different from the previous one. We added one cycle before the command read to get data from the socket as long as they arrive. Check.

    Clean file:

    
    [root@localhost ]# > /tmp/nginx_vs_apache.log
    Compile and run:
    [tolik@localhost ]$ gcc -o differ differ2.c
    [tolik@localhost ]$ ./differ
    First client:
    [tolik@localhost ]$ telnet localhost 2222
    Connected to localhost.
    Escape character is '^]'.
    client test 1
    yoyoyo
    
    Second client:
    [tolik@localhost ]$ telnet localhost 2222
    Connected to localhost.
    Escape character is '^]'.
    client test 2
    yooyoy
    Check what happened:
    [root@localhost ]# cat /tmp/nginx_vs_apache.log
    client test 1
    yoyoyo
    

    This time all is well, we took all of the data, but the problem remained: two connections are processed sequentially, one by one, and it does not fit our requirements. If we close the first connection (ctrl +]), the data from the second connection will be added directly in the log:

    
    [root@localhost ]# cat /tmp/nginx_vs_apache.log
    client test 1
    yoyoyo
    client test 2
    yooyoy
    

    The data came from. But how to process two connections in parallel? Here we comes to help the command fork. What does the system call fork in linux? The correct answer to this question on any job interview – nothing. Fork – outdated call, and it is presented in linux only for backward compatibility. In fact, calling command fork, you invoke the system call clone. Function clone creates a copy of the process and puts both processes in the queue to CPU. The difference between them is that a fork copies the data (variables, buffers, etc.) directly into the memory space of the child process, while clone copies the data to the child process only if you try to change them (see restrict memory access in the MMU). That is, if you call fork 10 times, and use the data to read-only, you will receive 10 identical copies of data in memory. And this is clearly not what you need, especially in multithread applications. Clone launches a copy of your application, but does not copy the data immediately. If you run clone 10 times, then you will have 10 executable processes with a single block of memory, and the memory will be copied only when you try to change the child process. Agree, the second algorithm is much more effective.
    Program c fork differ3.c

    
    #define PORT_NO 2222
    
    #include 
    #include 
    #include <netinet/in.h>
    
    int main(int argc, char *argv[])
    {
            int sockfd, newsockfd;
            socklen_t clilen;
            char buffer;
            char * pointbuffer = &buffer;
            struct sockaddr_in serv_addr, cli_addr;
            FILE * resultfile;
            int pid=1;
            resultfile = fopen("/tmp/nginx_vs_apache.log","a");
            bzero((char *) &serv_addr, sizeof(serv_addr));
            serv_addr.sin_family = AF_INET;
            serv_addr.sin_addr.s_addr = INADDR_ANY;
            serv_addr.sin_port = htons(PORT_NO);
            sockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (sockfd < 0) error("ERROR opening socket");
            if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error("ERROR on binding");
            listen(sockfd,50);
            while (pid!=0) {
                    newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
                    if (newsockfd < 0) error("ERROR on accept");
                    pid=fork();
                    if (pid!=0) {
                            close(newsockfd);
                            fprintf(resultfile,"New process was started with pid=%d\n",pid);
                            fflush (resultfile);
                    }
            }
            while (read(newsockfd, pointbuffer,1)) {
                            fprintf(resultfile, pointbuffer);
                            fflush (resultfile);
            }
            close(sockfd);
            return 0;
    }
    
    

    In this program all the same — we do accept, accept a new connection. Next, we run fork. And if it is the master process (fork returned pid of the created process), then we close the current connection in the parent process (it is available in the parent and in the child process). If it’s a child process (fork returned 0), then we start to read from the open socket that we opened by command accept in the parent process. In fact it turns out that the parent process only accepts connections and read/write we do in child processes.

    Compile and run:

    
    [tolik@localhost ]$ gcc -o differ differ3.c
    [tolik@localhost ]$ ./differ
    

    Clean our log file:

    
    [root@localhost ]# > /tmp/nginx_vs_apache.log
    

    Look processes:

    
    [root@localhost ]# ps axuf | grep [d]iffer
    tolik      45643  0.0  0.0   4060   460 pts/12   S+   01:40   0:00  |   \_ ./differ
    

    Client 1:

    
    [tolik@localhost ]$ telnet localhost 2222
    Connected to localhost.
    Escape character is '^]'.
    client 1 test
    megatest
    

    Client 2:

    
    [tolik@localhost ]$ telnet localhost 2222
    Connected to localhost.
    Escape character is '^]'.
    client2 test
    yoyoyoy
    

    Look processes:

    
    [root@localhost ]# ps axuf | grep [d]iffer
    tolik      45643  0.0  0.0   4060   504 pts/12   S+   01:40   0:00  |   \_ ./differ
    tolik      45663  0.0  0.0   4060   156 pts/12   S+   01:41   0:00  |       \_ ./differ
    tolik      45665  0.0  0.0   4060   160 pts/12   S+   01:41   0:00  |       \_ ./differ
    

    We do not close both connections and can get something else to add, see our log:

    
    [root@localhost ]# cat /tmp/nginx_vs_apache.log
    New process was started with pid=44163
    New process was started with pid=44165
    client 1 test
    megatest
    client2 test
    yoyoyoy
    

    Two connections are processed at the same time – we got the desired result.
    The program works, but not fast enough. It first accepts the connection and then runs the command fork, and the connection only handles one process. The question is: can multiple processes in Linux operating system to work with the same tcp port? Try.

    Program c pre differ_prefork fork.c

    
    #define PORT_NO 2222
    
    #include 
    #include 
    #include <netinet/in.h>
    
    int main(int argc, char *argv[])
    {
            int sockfd, newsockfd, startservers, count ;
            socklen_t clilen;
            char buffer;
            char * pointbuffer = &buffer;
            struct sockaddr_in serv_addr, cli_addr;
            FILE * resultfile;
            int pid=1;
            resultfile = fopen("/tmp/nginx_vs_apache.log","a");
            bzero((char *) &serv_addr, sizeof(serv_addr));
            serv_addr.sin_family = AF_INET;
            serv_addr.sin_addr.s_addr = INADDR_ANY;
            serv_addr.sin_port = htons(PORT_NO);
            sockfd = socket(AF_INET, SOCK_STREAM, 0);
            if (sockfd < 0) error("ERROR opening socket");
            if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error("ERROR on binding");
            listen(sockfd,50);
            startservers=2;
            count = 0;
            while (pid!=0) {
                    if (count < startservers)
                    {
                            pid=fork();
                                    if (pid!=0) {
                                    close(newsockfd);
                                    fprintf(resultfile,"New process was started with pid=%d\n",pid);
                                    fflush (resultfile);
                            }
                    count = count + 1;
                    }
                    //sleep (1);
            }
            newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
            if (newsockfd < 0) error("ERROR on accept");
            while (read(newsockfd, pointbuffer,1)) {
                            fprintf(resultfile, pointbuffer);
                            fflush (resultfile);
            }
            close(sockfd);
            return 0;
    }
    

    As you can see, the program still has not changed much, we just run a fork through the cycle. In this case, we create two child processes, and then each of them does accept to accept a new connection. Check.

    Compile and run:

    
    [tolik@localhost ]$ gcc -o differ differ_prefork.c
    [tolik@localhost ]$ ./differ
    

    Look processes:

    
    [root@localhost ]# ps axuf | grep [d]iffer
    tolik      44194 98.0  0.0   4060   504 pts/12   R+   23:35   0:07  |   \_ ./differ
    tolik      44195  0.0  0.0   4060   152 pts/12   S+   23:35   0:00  |       \_ ./differ
    tolik      44196  0.0  0.0   4060   156 pts/12   S+   23:35   0:00  |       \_ ./differ
    

    We have not joined any of the clients, and the program has already twice made fork. What is happening with the system? For beginning the master process: it is a closed loop and checks whether it is necessary to fork other processes. If we do it without stopping, then, in fact, will constantly require from OS CPU time, as our cycle must always be executed. This means that we consume 100% of one kernel in the command ps value is 98.0%. The same can be seen in the command top:

    
    [root@localhost ]# top -n 1 | head
    top - 23:39:22 up 141 days, 21 min,  8 users,  load average: 1.03, 0.59, 0.23
    Tasks: 195 total,   2 running, 193 sleeping,   0 stopped,   0 zombie
    Cpu(s):  0.3%us,  0.2%sy,  0.0%ni, 99.3%id,  0.2%wa,  0.0%hi,  0.0%si,  0.0%st
    Mem:   1896936k total,  1876280k used,    20656k free,   151208k buffers
    Swap:  4194296k total,   107600k used,  4086696k free,  1003568k cached
    
        PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
      44194 tolik     20   0  4060  504  420 R 98.9  0.0   4:10.54 differ
      44255 root      20   0 15028 1256  884 R  3.8  0.1   0:00.03 top
          1 root      20   0 19232  548  380 S  0.0  0.0   2:17.17 init
    

    If we connect the command strace to the parent, we won’t see anything, because our process does not cause any kernel functions:

    
    [root@localhost ]# strace -p 44194
    Process 44194 attached - interrupt to quit
    ^CProcess 44194 detached
    [root@localhost ]#
    

    What do child processes? Then the fun begins. Judging by the code, all of them after the fork should be hanging in a state of accept and expect new connections from the same port, in our case is 2222. Check:

    
    [root@localhost ]# strace -p 44195
    Process 44195 attached - interrupt to quit
    accept(4, ^C 
    Process 44195 detached
    [root@localhost ]# strace -p 44196
    Process 44196 attached - interrupt to quit
    accept(4, ^C 
    Process 44196 detached
    

    At the moment, they do not require OS CPU time and consume only memory. But here’s the question: who of them will accept my connection, if I do telnet? Check:

    
    [tolik@localhost ]$ telnet localhost 2222
    Connected to localhost.
    Escape character is '^]'.
    client 1 test
    hhh
    [root@localhost ]# strace -p 44459
    Process 44459 attached - interrupt to quit
    read(5, ^C 
    Process 44459 detached
    [root@localhost ]# strace -p 44460
    Process 44460 attached - interrupt to quit
    accept(4, ^C 
    Process 44460 detached
    

    We see that the process that was created earlier (with a lower pid), processed connection of the first, and now is in the read state. If we start a second telnet, the connection will process the following process. After we have finished with the socket, we can close it and go again to the state accept (I do not, in order not to complicate the program).
    Last question remains: what do we do with the parent process so that it does not consume so much cpu and it continued to work? We need to give time to other processes voluntarily, that is “to say” our OS, that for some time we do not need cpu. For this task suitable command sleep 1: if you uncomment it, you will see in strace picture, which repeats once per second:

    
    [root@localhost ]# strace -p 44601
    …..
    rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
    rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
    rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
    nanosleep({1, 0}, 0x7fff60a15aa0)       = 0
    ….
    rt_sigprocmask(SIG_BLOCK, [CHLD], [], 8) = 0
    rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, 8) = 0
    rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
    nanosleep({1, 0}, 0x7fff60a15aa0)        = 0
    …
    etc.
    

    Our process will get the CPU about once per second, or at least require it from the OS.
    If you still don’t understand what this long article, then look at the apache httpd running in prefork mode:

    
    [root@www /]# ps axuf | grep [h]ttpd
    root     12730  0.0  0.5 271560 11916 ?        Ss   Feb25   3:14 /usr/sbin/httpd
    apache   19832  0.0  0.3 271692  7200 ?        S    Apr17   0:00  \_ /usr/sbin/httpd
    apache   19833  0.0  0.3 271692  7212 ?        S    Apr17   0:00  \_ /usr/sbin/httpd
    apache   19834  0.0  0.3 271692  7204 ?        S    Apr17   0:00  \_ /usr/sbin/httpd
    apache   19835  0.0  0.3 271692  7200 ?        S    Apr17   0:00  \_ /usr/sbin/httpd
    

    Child processes in accept:

    
    [root@www /]# strace -p 19832
    Process 19832 attached
    accept4(3, ^CProcess 19832 detached
     
    [root@www /]# strace -p 19833
    Process 19833 attached
    accept4(3, ^CProcess 19833 detached
     
    

    The master process with a second pause:

    
    [root@www /]# strace -p 12730
    Process 12730 attached
    select(0, NULL, NULL, NULL, {0, 629715}) = 0 (Timeout)
    wait4(-1, 0x7fff4c9e3fbc, WNOHANG|WSTOPPED, NULL) = 0
    select(0, NULL, NULL, NULL, {1, 0})     = 0 (Timeout)
    wait4(-1, 0x7fff4c9e3fbc, WNOHANG|WSTOPPED, NULL) = 0
    select(0, NULL, NULL, NULL, {1, 0})     = 0 (Timeout)
    wait4(-1, 0x7fff4c9e3fbc, WNOHANG|WSTOPPED, NULL) = 0
    

    When you start the httpd master process spawns child processes, it is easy to see if you run strace on the master process at the time of the launch:

    Run a web server with the following settings:

    
    StartServers       1
    MinSpareServers    9
    MaxSpareServers   10
    ServerLimit       10
    MaxClients        10
    MaxRequestsPerChild  1
    

    These settings say that each child process will handle only a one request, and then process will be killed. The minimum number of processes in accept is 9 and maximum is 10.

    If you run strace on the master process at the start, we see how the master calls the clone until it reaches MinSpareServers.

    Tracing

    
    rt_sigaction(SIGSEGV, {0x7f9991933c20, [], SA_RESTORER|SA_RESETHAND, 0x7f99901dd500}, NULL, 8) = 0
    rt_sigaction(SIGBUS, {0x7f9991933c20, [], SA_RESTORER|SA_RESETHAND, 0x7f99901dd500}, NULL, 8) = 0
    rt_sigaction(SIGABRT, {0x7f9991933c20, [], SA_RESTORER|SA_RESETHAND, 0x7f99901dd500}, NULL, 8) = 0
    rt_sigaction(SIGILL, {0x7f9991933c20, [], SA_RESTORER|SA_RESETHAND, 0x7f99901dd500}, NULL, 8) = 0
    rt_sigaction(SIGFPE, {0x7f9991933c20, [], SA_RESTORER|SA_RESETHAND, 0x7f99901dd500}, NULL, 8) = 0
    rt_sigaction(SIGTERM, {0x7f999193de50, [], SA_RESTORER, 0x7f99901dd500}, NULL, 8) = 0
    rt_sigaction(SIGWINCH, {0x7f999193de50, [], SA_RESTORER, 0x7f99901dd500}, NULL, 8) = 0
    rt_sigaction(SIGINT, {0x7f999193de50, [], SA_RESTORER, 0x7f99901dd500}, NULL, 8) = 0
    rt_sigaction(SIGXCPU, {SIG_DFL, [], SA_RESTORER, 0x7f99901dd500}, NULL, 8) = 0
    rt_sigaction(SIGXFSZ, {SIG_IGN, [], SA_RESTORER, 0x7f99901dd500}, NULL, 8) = 0
    rt_sigaction(SIGPIPE, {SIG_IGN, [], SA_RESTORER, 0x7f99901dd500}, NULL, 8) = 0
    rt_sigaction(SIGHUP, {0x7f999193de80, [HUP USR1], SA_RESTORER, 0x7f99901dd500}, NULL, 8) = 0
    rt_sigaction(SIGUSR1, {0x7f999193de80, [HUP USR1], SA_RESTORER, 0x7f99901dd500}, NULL, 8) = 0
    clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13098
    write(2, "[Wed Jan 25 13:24:39 2017] [noti"..., 114) = 114
    wait4(-1, 0x7fffae295fdc, WNOHANG|WSTOPPED, NULL) = 0
    select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
    clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13099
    wait4(-1, 0x7fffae295fdc, WNOHANG|WSTOPPED, NULL) = 0
    select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
    clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13100
    clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13101
    wait4(-1, 0x7fffae295fdc, WNOHANG|WSTOPPED, NULL) = 0
    select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
    clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13102
    clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13103
    clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13104
    clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13105
    wait4(-1, 0x7fffae295fdc, WNOHANG|WSTOPPED, NULL) = 0
    select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
    clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13106
    clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f99918eeab0) = 13107
    wait4(-1, 0x7fffae295fdc, WNOHANG|WSTOPPED, NULL) = 0
    select(0, NULL, NULL, NULL, {1, 0}) = 0 (Timeout)
    

    Watch how apache starts – it can easy to look ps axuf | grep [h]ttp every second immediately after the start.

    Start apache

    
    [root@www /]# date; ps axuf | grep [h]ttp
    Wed Jan 25 14:12:10 EST 2017
    root 13342 2.5 0.4 271084 9384? Ss 14:12 0:00 /usr/sbin/httpd
    apache 13344 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    
    [root@www /]# date; ps axuf | grep [h]ttp
    Wed Jan 25 14:12:11 EST 2017
    root 13342 1.6 0.4 271084 9384? Ss 14:12 0:00 /usr/sbin/httpd
    apache 13344 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13348 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    
    [root@www /]# date; ps axuf | grep [h]ttp
    Wed Jan 25 14:12:11 EST 2017
    root 13342 2.0 0.4 271084 9384? Ss 14:12 0:00 /usr/sbin/httpd
    apache 13344 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13348 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13352 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13353 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    
    [root@www /]# date; ps axuf | grep [h]ttp
    Wed Jan 25 14:12:12 EST 2017
    root 13342 1.7 0.4 271084 9384? Ss 14:12 0:00 /usr/sbin/httpd
    apache 13344 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13348 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13352 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13353 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13357 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13358 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13359 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13360 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    
    [root@www /]# date; ps axuf | grep [h]ttp
    Wed Jan 25 14:12:13 EST 2017
    root 13342 1.4 0.4 271084 9384? Ss 14:12 0:00 /usr/sbin/httpd
    apache 13344 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13348 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13352 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13353 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13357 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13358 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13359 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13360 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13364 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    apache 13365 0.0 0.2 271084 5232? S 14:12 0:00 _ /usr/sbin/httpd
    [root@www /]#
    

    So, we have several child processes that are ready to make our http request. Let’s try to send the request:

    
    [root@www /]# wget -O /dev/null http://localhost
    --2017-01-25 14:04:00--  http://localhost/
    Resolving localhost... ::1, 127.0.0.1
    Connecting to localhost|::1|:80... failed: Connection refused.
    Connecting to localhost|127.0.0.1|:80... connected.
    HTTP request sent, awaiting response... 403 Forbidden
    2017-01-25 14:04:00 ERROR 403: Forbidden.
    

    Apache answered us 403, look at the process:

    
    root     13342  0.0  0.4 271084  9384 ?        Ss   14:12   0:00 /usr/sbin/httpd
    apache   13348  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13352  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13353  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13357  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13358  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13359  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13360  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13364  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13365  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    

    As you can see, the process with minimal pid has processed the request and concluded its work:

    
    apache   13344  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    

    Child processes we have got 9 that fits into our limit MinSpareServers.
    Try again to send the request:

    
    [root@www /]# wget -O /dev/null http://localhost
    --2017-01-25 14:15:47--  http://localhost/
    Resolving localhost... ::1, 127.0.0.1
    Connecting to localhost|::1|:80... failed: Connection refused.
    Connecting to localhost|127.0.0.1|:80... connected.
    HTTP request sent, awaiting response... 403 Forbidden
    2017-01-25 14:15:47 ERROR 403: Forbidden.
    [root@www /]# ps axuf | grep [h]ttp
    root     13342  0.0  0.4 271084  9384 ?        Ss   14:12   0:00 /usr/sbin/httpd
    apache   13352  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13353  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13357  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13358  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13359  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13360  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13364  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13365  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13373  0.0  0.2 271084  5232 ?        S    14:15   0:00  \_ /usr/sbin/httpd
    

    This time our request was processed the process

    
    apache   13348  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    

    because now it has minimal pid.
    But we have got 8 free child processes in accept, one is not enough to MinSpareServers, so the master process have created a new process:

    
    apache   13373  0.0  0.2 271084  5232 ?        S    14:15   0:00  \_ /usr/sbin/httpd
    

    Let’s say our OS that it does not give the CPU time to the master process of apache:

    
    [root@www /]# kill -SIGSTOP 13342
    

    The process status has changed, now it doesn’t work.
    Check whether we have a web server is running:

    
    [root@www /]# wget -O /dev/null http://localhost
    --2017-01-25 14:20:12--  http://localhost/
    Resolving localhost... ::1, 127.0.0.1
    Connecting to localhost|::1|:80... failed: Connection refused.
    Connecting to localhost|127.0.0.1|:80... connected.
    HTTP request sent, awaiting response... 403 Forbidden
    2017-01-25 14:20:12 ERROR 403: Forbidden.
    

    Oh yes, still running, the web server is still responding.
    Look what we have with the process:

    
    root     13342  0.0  0.4 271084  9384 ?        Ts   14:12   0:00 /usr/sbin/httpd
    apache   13352  0.0  0.0      0     0 ?        Z    14:12   0:00  \_ [httpd] 
    apache   13353  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13357  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13358  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13359  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13360  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13364  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13365  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13373  0.0  0.2 271084  5232 ?        S    14:15   0:00  \_ /usr/sbin/httpd
    

    Our next request was processed by the next child process, which worked and left. But it left the exit code, which must be processed by the master process. Since the master process is stopped, then the exit code is in the kernel in the process table, and though we don’t have a process there, but in the table it is marked as a zombie.

    
    apache   13352  0.0  0.0      0     0 ?        Z    14:12   0:00  \_ [httpd] 
    

    Naturally the child processes we have 8 new, as the new 9th produce none, master stopped.

    Let’s experiment will send another http request:

    
    [root@www /]# wget -O /dev/null http://localhost
    --2017-01-25 14:25:03--  http://localhost/
    Resolving localhost... ::1, 127.0.0.1
    Connecting to localhost|::1|:80... failed: Connection refused.
    Connecting to localhost|127.0.0.1|:80... connected.
    HTTP request sent, awaiting response... 403 Forbidden
    2017-01-25 14:25:03 ERROR 403: Forbidden.
    [root@www /]# ps axuf | grep [h]ttp
    root     13342  0.0  0.4 271084  9384 ?        Ts   14:12   0:00 /usr/sbin/httpd
    apache   13352  0.0  0.0      0     0 ?        Z    14:12   0:00  \_ [httpd] 
    apache   13353  0.0  0.0      0     0 ?        Z    14:12   0:00  \_ [httpd] 
    apache   13357  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13358  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13359  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13360  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13364  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13365  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13373  0.0  0.2 271084  5232 ?        S    14:15   0:00  \_ /usr/sbin/httpd
    

    Logically, the situation is repeated.

    Let’s say our OS is that the master process can continue to run again:

    
    [root@www /]# kill -SIGCONT 13342
    [root@www /]# ps axuf | grep [h]ttp
    root     13342  0.0  0.4 271084  9384 ?        Ss   14:12   0:00 /usr/sbin/httpd
    apache   13357  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13358  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13359  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13360  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13364  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13365  0.0  0.2 271084  5232 ?        S    14:12   0:00  \_ /usr/sbin/httpd
    apache   13373  0.0  0.2 271084  5232 ?        S    14:15   0:00  \_ /usr/sbin/httpd
    apache   13388  0.0  0.2 271084  5232 ?        S    14:26   0:00  \_ /usr/sbin/httpd
    apache   13389  0.0  0.2 271084  5232 ?        S    14:26   0:00  \_ /usr/sbin/httpd
    apache   13390  0.0  0.2 271084  5232 ?        S    14:26   0:00  \_ /usr/sbin/httpd
    

    The master process immediately read exit code of child processes, and references to them are gone from the process table and the missing processes in the master process to clone again — we now have 10 free processes in accept that fit into the framework of our variables from configs.

    How does nginx? As you know, the system call accept blocks execution of our program as long as no new connection will come. It turns out that we can’t expect a new connection and process already open connection in one process. Or?

    Take a look at the code:

    Code with select

    
    #define PORT 2222
    #include 
    #include    
    #include 
    #include 
    #include    
    #include <arpa/inet.h>    
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <sys/time.h>
    
    int main(int argc , char *argv[])
    {
            int opt = 1;
            int master_socket , addrlen , new_socket , client_socket[30] , max_clients = 30 , activity, i , valread , sd;
            int max_sd;
            FILE * resultfile;
            struct sockaddr_in address;
            char buffer[50];
            fd_set readfds;
            resultfile = fopen("/tmp/nginx_vs_apache.log","a");
          // Fill our array of sockets with zeros
            for (i = 0; i < max_clients; i++)  client_socket[i] = 0;
            if( (master_socket = socket(AF_INET , SOCK_STREAM , 0)) == 0)  error("socket failed");
            address.sin_family = AF_INET;
            address.sin_addr.s_addr = INADDR_ANY;
            address.sin_port = htons( PORT );
            if (bind(master_socket, (struct sockaddr *)&address, sizeof(address))<0) error("bind failed");
            if (listen(master_socket, 3) < 0) error("listen");
            addrlen = sizeof(address);
            while(1) //in an endless loop process requests
            {
                FD_ZERO(&readfds);
                FD_SET(master_socket, &readfds);
                max_sd = master_socket;
                for ( i = 0 ; i < max_clients ; i++) { sd = client_socket[i]; if(sd > 0) FD_SET( sd , &readfds);
                    if(sd > max_sd) max_sd = sd;
                }
                // Waiting for events on any of sockets we are interested in
                activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);
                if ((activity < 0) && (errno!=EINTR))  printf("select error");
                // Processing a new connection
                if (FD_ISSET(master_socket, &readfds))
                {
                    if ((new_socket = accept(master_socket, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) error("accept");
                    for (i = 0; i < max_clients; i++)
                        if( client_socket[i] == 0 ) { client_socket[i] = new_socket; break; }
                }
    
                // Read data from each socket, as we do not know what events caused the OS to give us the CPU
                for (i = 0; i < max_clients; i++)
                {
                    sd = client_socket[i];
                    if (FD_ISSET( sd , &readfds))
                    {
                        if ((valread = read( sd , buffer, 1024)) == 0) { close( sd ); client_socket[i] = 0; }
                        else
                        {
                            buffer[valread] = '\0';
                            fprintf(resultfile, buffer);
                            fflush (resultfile);
                        }
                    }
                }
            }
    
            return 0;
    }
    

    This code looks a bit more complicated than the previous one, but it’s quite easy to explain. For example, in the process need to handle a maximum of 30 connections. We create an array of zeros. As soon as we come to the new connection, we are processing it, and the socket address is recorded in this array. Going through the entire array and all of our sockets, we can consistently read information from them. But how do we know about the new connection without the use of accept? In linux for that there are at least 3 functions: select, poll and epoll. And in freebsd this is the analogue of the function epoll called kqueue (kernel queue). What these commands do? select the oldest feature which is still used in order to give all CPU time to the kernel, requesting it only when certain conditions (like accept). The difference is that the kernel will return cpu to us, when we have specified sockets will start any activity. Because when you start the program open only one socket in select we specify one. If we connect via Telnet to our daemon, in select we need to specify two sockets: the master socket on port 2222 and one that has connected to us. To make it clearer, demonstrate:

    
    [tolik@101host nginx_vs_apache]$ ./differ &
    [1] 44832
    [tolik@101host nginx_vs_apache]$ ps axuf | grep [.]/differ
    tolik     44832 0.0  0.0   4060   448 pts/0    S    22:47   0:00              \_ ./differ
    [root@localhost ]# strace -p 44832
    Process 44832 attached - interrupt to quit
    select(5, [4], NULL, NULL, NULL)        = 1 (in [4])
    

    At this point we make another console telnet on the port 2222 in our daemon and look at the trace:

    
    accept(4, {sa_family=AF_INET, sin_port=htons(41130), sin_addr=inet_addr("127.0.0.1")}, [16]) = 5
    select(6, [4 5], NULL, NULL, NULL^C 
    Process 44832 detached
    [root@localhost ]# ls -lh /proc/44832/fd
    итого 0
    lrwx------ 1 tolik tolik 64 Апр 19 00:26 0 -> /dev/pts/12
    lrwx------ 1 tolik tolik 64 Апр 19 00:26 1 -> /dev/pts/12
    lrwx------ 1 tolik tolik 64 Апр 19 00:21 2 -> /dev/pts/12
    l-wx------ 1 tolik tolik 64 Апр 19 00:26 3 -> /tmp/nginx_vs_apache.log
    lrwx------ 1 tolik tolik 64 Апр 19 00:26 4 -> socket:[42651147]
    lrwx------ 1 tolik tolik 64 Апр 19 00:26 5 -> socket:[42651320] 
    [root@localhost ]# netstat -apeen | grep 42651147
    tcp        0      0 0.0.0.0:2222                0.0.0.0:*                   LISTEN      500        42651147   44832/./differ
    [root@localhost ]# netstat -apeen | grep 42651320
    tcp        0      0 127.0.0.1:2222              127.0.0.1:41130             ESTABLISHED 500        42651320   44832/./differ
    

    First, the command select we have specified the socket 4 (see in brackets). According /proc we learned that the 4th file descriptor is a socket with the number 42651147. According to netstat, we found out that the socket number is our socket in state listen of port 2222. Once we have connected to this socket, the OS made a tcp handshake with our telnet client and installed the new connection, which is notified via the application select. Our program has received the CPU time and began to process an empty array with connections. Seeing that it is a new connection, we run the command accept, knowing that it will not block the program from running, because the connection is already present. In fact, we use the same accept, only in non-blocking mode.

    After we have completed the connection, we again gave control of the linux kernel, but told him that now we want to receive a notice on two sockets, under the number 4 and 5, which is very clearly visible in the command strace ([4 5]). This is how nginx works: it can handle a large number of sockets by one process. According to the existing sockets, we can conduct operations read/write, according to the new can call accept. Select is a very old system call has a number of limitations: for example, the maximum number of connections (file descriptors). It was replaced by a more perfect system call poll, devoid of these limits and working faster. Subsequently appeared epoll and kqueue (in freebsd). More advanced functions allow you to work more effectively with the connection.

    Which of these functions supports nginx? Nginx is able to work with all these features.

    A link to the documentation. In this article I will not describe the differences between all these functions, because the amount of text is already big enough.

    Nginx uses fork to create processes and to load all kernels on the server. But every single child process running nginx with multiple connections in the same way as in the example with select, only uses modern features for this (for linux the default is epoll). Take a look:

    
    [root@localhost ]# ps axuf| grep [n]ginx
    root      232753  0.0  0.0  96592   556 ?        Ss   Feb25   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
    nginx     232754  0.0  0.0  97428  1400 ?        S    Feb25   5:20  \_ nginx: worker process
    nginx     232755  0.0  0.0  97460  1364 ?        S    Feb25   5:02  \_ nginx: worker process
    [root@localhost ]# strace -p 232754
    Process 232754 attached - interrupt to quit
    epoll_wait(12, ^C 
    Process 232754 detached
    [root@localhost ]# strace -p 232755
    Process 232755 attached - interrupt to quit
    epoll_wait(14, {}, 512, 500)            = 0
    epoll_wait(14, ^C 
    Process 232755 detached
    

    What makes a parent master process nginx?

    
    [root@localhost ]# strace -p 232753
    Process 232753 attached - interrupt to quit
    rt_sigsuspend([]^C 
    Process 232753 detached
    

    It does not accept incoming connections, and only waiting for a signal from the OS. At the signal, nginx is able to a lot of interesting things, for example, to reopen file descriptors, which is useful when log rotation, or to reread the configuration file.

    All interaction between processes nginx carries using unix sockets:

    
    [root@localhost ]# ls -lh /proc/232754/fd
    итого 0
    lrwx------ 1 nginx nginx 64 Апр  8 13:20 0 -> /dev/null
    lrwx------ 1 nginx nginx 64 Апр  8 13:20 1 -> /dev/null
    lrwx------ 1 nginx nginx 64 Апр  8 13:20 10 -> socket:[25069547]
    lrwx------ 1 nginx nginx 64 Апр  8 13:20 11 -> socket:[25069551]
    lrwx------ 1 nginx nginx 64 Апр  8 13:20 12 -> anon_inode:[eventpoll]
    lrwx------ 1 nginx nginx 64 Апр  8 13:20 13 -> anon_inode:[eventfd]
    l-wx------ 1 nginx nginx 64 Апр  8 13:20 2 -> /var/log/nginx/error.log
    lrwx------ 1 nginx nginx 64 Апр  8 13:20 3 -> socket:[25069552]
    l-wx------ 1 nginx nginx 64 Апр  8 13:20 5 -> /var/log/nginx/error.log
    l-wx------ 1 nginx nginx 64 Апр  8 13:20 6 -> /var/log/nginx/access.log
    lrwx------ 1 nginx nginx 64 Апр  8 13:20 9 -> socket:[25069546]
    [root@localhost ]# netstat -apeen | grep 25069547
    tcp        0      0 172.16.0.1:80               0.0.0.0:*                   LISTEN      0          25069547   232753/nginx
    [root@localhost ]# netstat -apeen | grep 25069551
    unix  3      [ ]         STREAM     CONNECTED     25069551 232753/nginx
    

    Result

    Before choosing the tools, it is important to understand exactly how they work. So in some cases it is better to use only apache without httpd nginx – and vice versa. But most often these products are used together, because the parallel processing of sockets in apache is engaged by OS (different processes), and parallel processing of sockets in nginx does nginx itself.

    P.S.
    If after compiling programs do not run, make sure that you do not open the connection on port 2222. In the program I did not handle the situation by closing the sockets, and they can be some time still open in different states from the old demons. If the program does not start, just wait until all sockets are closed by timeout.

    This text is a translation of the article “Разница между nginx и apache с примерами”  published by @mechanicusilius on habrahabr.ru.

    About the CleanTalk service

    CleanTalk is a cloud service to protect websites from spambots. CleanTalk uses protection methods that are invisible to the visitors of the website. This allows you to abandon the methods of protection that require the user to prove that he is a human (captcha, question-answer etc.).

  • New features for spam comments management on WordPress

    New features for spam comments management on WordPress

    For WordPress users of the service, we have added the new possibilities to manage spam comments.
    By default, all spam comments are placed in the spam folder, now you can change the way the plugin deals with spam comments:

    1. Move to Spam Folder. You can prevent the proliferation of spam folder. It can be cleaned automatically using the option “Keep spam comments for 15 days.” Enable this option in the settings of the plugin: WP Dashboard-Settings-Anti-Spam by CleanTalk->

    2. Move to Trash. All spam comments will be placed in the folder “Trash” in the WordPress Comments section except comments with Stop-Words. Stop-Word comments will be always stored in the “Pending” folder.

    3. Ban comments without moving to WordPress Backend. All spam comments will be deleted permanently without going to the WordPress backend except comments with Stop-Words. Stop-Word comments will be always stored in the “Pending” folder. What comments were blocked and banned can be seen in the Anti-Spam Log.

    To manage the actions with spam comments, go to the Control Panel, select the website you want to change the actions for and go to “Settings” under the name of the website. On the website settings page, select the item from the “SPAM comment action:” the necessary settings and click “Save” button at the bottom of the page.

  • Exotic HTTP headers

    Hello! This article will illustrate the result of applying some important and exotic HTTP headers, most of which are related to security.

    X-XSS-Protection

    Attack XSS (cross-site scripting) is a type of attack in which malicious code can be embedded in the target page.
    For example like this:

    <h1>Hello, <script>alert('hacked')</script></h1>

    This type of attacks easy to detect and the browser may handle it: if the source code contains part of the request, it may be a threat.

    And the title X-XSS-Protection manages the behavior of the browser.

    Accepted values:

    • 0 the filter is turned off
    • 1 filter is enabled. If the attack is detected, the browser will remove the malicious code.
    • 1; mode=block. The filter is enabled, but if the attack is detected, the page will not be loaded by the browser.
    • 1; report=http://domain/url. the filter is enabled and the browser will clear the page from malicious code while reporting the attempted attack. Here, we use a function Chromium for reporting violation of content security policy (CSP) to a specific address.

    Create a web server sandbox on node.js to see how it works.

    
    var express = require('express')
    var app = express()
    app.use((req, res) => {
     if (req.query.xss) res.setHeader('X-XSS-Protection', req.query.xss)
    res.send(`<h1>Hello, ${req.query.user || 'anonymous'}</h1>`)
    })
    
    app.listen(1234)
    
    

    I will use Google Chrome 55.

    No title
    http://localhost:1234/?user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E

    Nothing happens, the browser will successfully block the attack. Chrome, by default, blocks the threat and reported it to the console.

    It even highlights the problem area in the source code.

    X-XSS-Protection: 0

    http://localhost:1234/?user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E&xss=0

    Oh no!

    X-XSS-Protection: 1

    http://localhost:1234/?user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E&xss=1

    Page was cleared because of the explicit title.0

    X-XSS-Protection: 1; mode=block

    http://localhost:1234/?user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E&xss=1;%20mode=block

    In this case, the attack will be prevented by blocking the page load.

    X-XSS-Protection: 1; report=http://localhost:1234/report

    http://localhost:1234/?user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E&xss=1;%20report=http://localhost:1234/report

    The attack is prevented and a message is sent to the appropriate address.

    X-Frame-Options

    With this title you can protect yourself from the so-called Clickjacking.

    Imagine that the attacker has a channel on YouTube and he wants more followers.

    He can create a page with a button “Do not press”, which would mean that everyone will click on it necessarily. But over the button is completely transparent iframe and in this frame hides the channel page with the subscription button. Therefore, when you press the button, in fact, a user subscribes to a channel, unless of course, he was logged into YouTube.

    We will demonstrate that.

    First, you need to install the extension to ignore this header.

    Create a simple page.

    
    <style>
    button { background: red; color: white; padding: 10px 20px; border: none; cursor: pointer; }
    iframe { opacity: 0.8; z-index: 1; position: absolute; top: -570px; left: -80px; width: 500px; height: 650px; }</style>
    
    <button>Do not click his button!</button>
    <iframe src="https://youtu.be/dQw4w9WgXcQ?t=3m33s"></iframe>
    

    As you can see, I have placed the frame with the subscription right over the button (z-index: 1) and so if you try to click it, you actually press the frame. In this example, the frame is not fully transparent, but it can be fixed with the value of opacity: 0.

    In practice, this doesn’t work, because YouTube set the desired heading, but the sense of threat, I hope, is clear.

    To prevent the page to be used in the frame need to use the title X-Frame-Options.

    Accepted values:

    • deny not load the page at all.
    • sameorigin not load if the source is not the same.
    • allow-from: DOMAIN you can specify the domain from which the page can be loaded in a frame.

    We need a web server to demonstrate

    var express = require('express')
    
     
    for (let port of [1234, 4321]) {
     var app = express()
    app.use('/iframe', (req, res) => res.send(`<h1>iframe</h1><iframe src="//localhost:1234?h=${req.query.h || ''}"></iframe>`))
    app.use((req, res) => {
      if (req.query.h) res.setHeader('X-Frame-Options', req.query.h)
    res.send('<h1>Website</h1>')
    })
    app.listen(port)
    }
    

    No title

    Everyone will be able to build our website on localhost:1234 in the frame.

    X-Frame-Options: deny

    The page cannot be used at all in the frame.

    X-Frame-Options: sameorigin

    Only pages with the same source will be able to be built into the frame. The sources are the same, if the domain, port and protocol are the same.

    X-Frame-Options: allow-from localhost:4321

    It seems that Chrome ignores this option, because there is a header Content-Security-Policy (about it will be discussed below). It does not work in Microsoft Edge.

    Below Mozilla Firefox.

    X-Content-Type-Options

    This header prevents attacks spoofing MIME type (<script src=”script.txt”>) or unauthorized hotlinking (<script src=”https://raw.githubusercontent.com/user/repo/branch/file.js”>)

    
    var express = require('express')
    var app = express()
    
    app.use('/script.txt', (req, res) => {
      if (req.query.h) res.header('X-Content-Type-Options', req.query.h)
    res.header('content-type', 'text/plain')
    res.send('alert("hacked")')
    })
    
    app.use((req, res) => {
    res.send(`<h1>Website</h1><script src="/script.txt?h=${req.query.h || ''}"></script>`
    })
    app.listen(1234)
    

    No title

    http://localhost:1234/

    Though script.txt is a text file with type text/plain, it will be launched as a script.

    X-Content-Type-Options: nosniff

    http://localhost:1234/?h=nosniff

    This time the types do not match and the file will not be executed.

    Content-Security-Policy

    It is a relatively new title and helps to reduce the risks of XSS attacks in modern browsers by specifying in the title what resources can be loaded on the page.

    For example, you can ask the browser do not execute inline-scripts and download files only from one domain. Inline-scripts can look not only like <script>…</script>, but also as <h1 onclick=”…”>.

    Let’s see how it works.

    
    var request = require('request')
    
    var express = require('express')
    
     
    
    for (let port of [1234, 4321]) {
    
    var app = express()
    
    app.use('/script.js', (req, res) => {
    
    res.send(`document.querySelector('#${req.query.id}').innerHTML = 'changed ${req.query.id}-script'`)
    
    })
    
    app.use((req, res) => {
    
    var csp = req.query.csp
    
    if (csp) res.header('Content-Security-Policy', csp)
    
    res.send(`
    
    <html>
    
    <body>
    
    <h1>Hello, ${req.query.user || 'anonymous'}</h1>
    
    <p id="inline">this will changed inline-script?</p>
    
    <p id="origin">this will changed origin-script?</p>
    
    <p id="remote">this will changed remote-script?</p>
    
    <script>document.querySelector('#inline').innerHTML = 'changed inline-script'</script>
    
    <script src="/script.js?id=origin"></script>
    
    <script src="//localhost:1234/script.js?id=remote"></script>
    
    </body>
    
    </html>
    
    `)
    
    })
    
    app.listen(port)
    
    }
    

    No title

    It works as you would expect

    Content-Security-Policy: default-src ‘none’

    http://localhost:4321/?csp=default-src%20%27none%27&user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E

    default-src applies a rule to all resources (images, scripts, frames, etc.), the value ‘none’ disables all. Below is shown what happens and the errors displayed in the browser.

    Chrome refused to run any scripts. In this case, you can’t even upload a favicon.ico.

    Content-Security-Policy: default-src ‘self’

    http://localhost:4321/?csp=default-src%20%27self%27&user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E

    Now it is possible to use the resources from one source but still cannot run external and inline-scripts.

    Content-Security-Policy: default-src ‘self’; script-src ‘self’ ‘unsafe-inline’

    http://localhost:4321/?csp=default-src%20%27self%27;%20script-src%20%27self%27%20%27unsafe-inline%27&user=%3Cscript%3Ealert(%27hacked%27)%3C/script%3E

    This time we let the execution and inline-scripts. Please note that XSS attack in the request was blocked too. But this will not happen if at the same time deliver and unsafe-inline and X-XSS-Protection: 0.

    Other values

    On the website, content-security-policy.com beautifully had shown many examples.

    • default-src ‘self’ allowed resources only from one source
    • script-src ‘self’ www.google-analytics.com ajax.googleapis.com allow Google Analytics, Google AJAX CDN, and resources from one source.
    • default-src ‘none’; script-src ‘self’; connect-src ‘self’; img-src ‘self’; style-src ‘self’; allow images, scripts, AJAX and CSS from one source and prohibit the downloading of any other resources. For most sites this is a good initial setting.

    I didn’t check, but I think that the following headers are equivalent:

    • frame-ancestors ‘none’ and X-Frame-Options: deny
    • frame-ancestors ‘self’ and X-Frame-Options: sameorigin
    • frame-ancestors localhost:4321 and X-Frame-Options: allow-from localhost:4321
    • script-src ‘self’ without ‘unsafe-inline’ and X-XSS-Protection: 1

    If you look at the headers facebook.com or twitter.com it is possible to notice that these sites use a lot of CSP.

    Strict-Transport-Security

    HTTP Strict Transport Security (HSTS) is a mechanism for security policy, which helps protect the website from attempts by an unsecured connection.

    Let’s say that we want to connect to facebook.com. If you don’t specify before requesting https://, protocol, by default, will be selected HTTP and therefore the request will look like http://facebook.com.

    
    $ curl -I facebook.com
    HTTP/1.1 301 Moved Permanently
    Location: https://facebook.com/
    

    After that, we will be redirected to the secure version of Facebook.

    If you connect to a public WiFi hotspot, which is owned by the attacker, the request may be intercepted and instead facebook.com the attacker may substitute a similar page to know the username and password.

    To guard against such an attack, you can use the aforementioned title that will tell the client the next time to use the https-version of the site.

    
    $ curl -I https://www.facebook.com/
    HTTP/1.1 200 OK
    Strict-Transport-Security: max-age=15552000; preload
    

    If the user was logged into Facebook at home and then tried to open it from an unsafe access point, he is not in danger, because browsers remember the title.

    But what happens if you connect to the unsecured network first time? In this case, the protection will not work.

    But browsers have a trump card in this case. They have a predefined list of domains for which should be used HTTPS only.

    You can send your domain at this address. It is also possible to find out whether the header is used correctly.

    Accepted values:

    • max-age=15552000 the time in seconds that the browser should remember the title.
    • includeSubDomains If you specify this optional value, the header applies to all subdomains.
    • preload if the site owner wants the domain got into a predefined list that is supported by Chrome (and used by Firefox and Safari).

    And if you need to switch to HTTP before the expiration of max-age or if you set preload? You can put the value max-age value=0 and then the navigation rule to the https version will stop to work.

    Public-Key-Pins

    HTTP Public Key Pinning (HPKP) is a mechanism for security policy that allows HTTPS sites to protect against malicious use of fake or fraudulent certificates.

    Accepted values:

    • pin-sha256=”<sha256>” in quotes is encoded using Base64 thumbprint of the Subject Public Key Information (SPKI). You can specify multiple pins for different public keys. Some browsers in the future may use other hashing algorithms besides SHA-256.
    • max-age=<seconds> the time, in seconds, that for access to the site need to use only the listed keys.
    • includeSubDomains if you specify this optional parameter, the title applies to all subdomains.
    • report-uri=”<URL>” if you specify URL, then when a validation error key, the corresponding message will be sent to the specified address.

    Instead of the title Public-Key-Pins, you can use Public-Key-Pins-Report-Only, in this case, it will only send the error messages to match the keys, but the browser will still load the page.

    So does Facebook:

    
    $ curl -I https://www.facebook.com/
    
    HTTP/1.1 200 OK
    
    ...
    
    Public-Key-Pins-Report-Only:
    
    max-age=500;
    
    pin-sha256="WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18=";
    
    pin-sha256="r/mIkG3eEpVdm+u/ko/cwxzOMo1bk4TyHIlByibiA5E=";
    
    pin-sha256="q4PO2G2cbkZhZ82+JgmRUyGMoAeozA+BSXVXQWB8XWQ=";
    
    report-uri="http://reports.fb.com/hpkp/"
    

    Why is it necessary? Not enough of trusted certification authorities (CA)?

    An attacker can create a certificate for facebook.com and by tricking the user to add it to your list of trusted certificates, or it can be an administrator.

    Let’s try to create a certificate for facebook.

    
    sudo mkdir /etc/certs
    
    echo -e 'US\nCA\nSF\nFB\nXX\nwww.facebook.com\nn*@**am.org' | \
    
    sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    
    -keyout /etc/certs/facebook.key \
    
    -out /etc/certs/facebook.crt
    

    And make it trusted in the local system.

    
    # curl
    
    sudo cp /etc/certs/*.crt /usr/local/share/ca-certificates/
    
    sudo update-ca-certificates
    
    # Google Chrome
    
    sudo apt install libnss3-tools -y
    
    certutil -A -t "C,," -n "FB" -d sql:$HOME/.pki/nssdb -i /etc/certs/facebook.crt
    
    # Mozilla Firefox
    
    #certutil -A -t "CP,," -n "FB" -d sql:`ls -1d $HOME/.mozilla/firefox/*.default | head -n 1` -i /etc/certs/facebook.crt
    

    Now run the web server using this certificate.

    
    var fs = require('fs')
    
    var https = require('https')
    
    var express = require('express')
    
     
    
    var options = {
    
    key: fs.readFileSync(`/etc/certs/${process.argv[2]}.key`),
    
    cert: fs.readFileSync(`/etc/certs/${process.argv[2]}.crt`)
    
    }
    
     
    
    var app = express()
    
    app.use((req, res) => res.send(`<h1>hacked</h1>`))
    
    https.createServer(options, app).listen(443)
    

    Switch to the server

    
    echo 127.0.0.1 www.facebook.com | sudo tee -a /etc/hosts
    
    sudo node server.js facebook
    

    Let’s see what happened

    
    $ curl https://www.facebook.com
    
    <h1>hacked</h1>
    

    Great. curl validates the certificate.

    So as I already went to Facebook and Google Chrome has seen its headers, it should report the attack but to allow the page, right?

    Nope. Keys are not checked because of local root certificate [Public key pinning bypassed]. This is interesting…

    Well, and what about www.google.com?

    
    echo -e 'US\nCA\nSF\nGoogle\nXX\nwww.google.com\nn*@**am.org' | \
    
    sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    
    -keyout /etc/certs/google.key \
    
    -out /etc/certs/google.crt
    
    sudo cp /etc/certs/*.crt /usr/local/share/ca-certificates/
    
    sudo update-ca-certificates
    
    certutil -A -t "C,," -n "Google" -d sql:$HOME/.pki/nssdb -i /etc/certs/google.crt
    
    echo 127.0.0.1 www.google.com | sudo tee -a /etc/hosts
    
    sudo node server.js google
    

    The same result. I think this is a feature.

    But in any case, if you do not add these certificates to the local store, open websites will not work because the option to continue with an insecure connection in Chrome or add an exception in Firefox will not.

    Content-Encoding: br

    Data is compressed with Brotli.

    The algorithm promises better compression than gzip and comparable speed unzipping. Supports Google Chrome.

    Of course, there is a module for in node.js.

    
    var shrinkRay = require('shrink-ray')
    
    var request = require('request')
    
    var express = require('express')
    
     
    
    request('https://www.gutenberg.org/files/1342/1342-0.txt', (err, res, text) => {
    
    if (err) throw new Error(err)
    
    var app = express()
    
    app.use(shrinkRay())
    
    app.use((req, res) => res.header('content-type', 'text/plain').send(text))
    
    app.listen(1234)
    
    })
    

    Original size: 700 KB

    Brotli: 204 KB

    Gzip: 241 KB

    Timing-Allow-Origin

    Using the Resource Timing API, you can find out how much time took the processing of resources on the page.

    Because the information of load-time may be used to determine whether the user visited the page before this (paying attention to the fact that resources can be cached), a standard is considered to be vulnerable, if you give this information to any hosts.

    
    <script>
    
    setTimeout(function() {
    
    console.log(window.performance.getEntriesByType('resource'))
    
    }, 1000)
    
    </script>
    
     
    
    <img src="http://placehold.it/350x150">
    
    <img src="/local.gif">
    

    It seems that if you do not specify Timing-Allow-Origin, then get detailed information about the time of the operations (the search domain, for example) is possible only for resources with one source.

    You can use this:

    • Timing-Allow-Origin: *
    • Timing-Allow-Origin: http://foo.com http://bar.com

    Alt-Svc

    The Alternative Services allow resources to be in different parts of the network and access to them can be obtained using different configurations of the protocol.

    This is used in Google:

    • alt-svc: quic=”:443″; ma=2592000; v=”36,35,34″

    This means that the browser, if it wish, can use the QUIC, it is HTTP over UDP, over port 443 the next 30 days (ma = 2592000 seconds, or 720 hours, i.e. 30 days). I have no idea what means the parameter v, version?

    P3P

    Below are some P3P headers that I have seen:

    • P3P: CP=«This is not a P3P policy! See support.google.com/accounts/answer/151657?hl=en for more info.»
    • P3P: CP=«Facebook does not have a P3P policy. Learn why here: fb.me/p3p»

    Some browsers require that cookies of third parties supported the P3P protocol for designation of confidentiality measures.

    The organization, founded P3P, the world wide web Consortium (W3C) halted work on the protocol a few years ago due to the fact that modern browsers don’t end up to support protocol. As a result, P3P is outdated and does not include technologies that are now used in a network, so most sites do not support P3P.

    I didn’t go too far, but apparently the header is needed for IE8 to accept cookies from third parties.

    For example, if IE privacy settings are high, then all cookies from sites that do not have a compact privacy policy will be blocked, but those who have headlines similar to the above, will not be blocked.

    Which of the following HTTP headers You use in projects?

    X-XSS-Protection
    X-Frame-Options
    X-Content-Type-Options
    Content-Security-Policy
    Strict-Transport-Security
    Public-Key-Pins
    Content-Encoding
    Timing-Allow-Origin
    Alt-Svc
    P3P
    Other

    This text is a translation of the article “Экзотичные заголовки HTTP”  published by @A3a on habrahabr.ru.

    About the CleanTalk service

    CleanTalk is a cloud service to protect websites from spambots. CleanTalk uses protection methods that are invisible to the visitors of the website. This allows you to abandon the methods of protection that require the user to prove that he is a human (captcha, question-answer etc.).

  • About SomeInspiration.com

    Hello, I’m Francis O’Neill, and, among other things, such as looking after the website I’m about to tell you about, I now view myself as a writer. I write on spiritual health and mind, body & spirit topics. I have a couple of books out at this time. In many respects this also encapsulates my business.

    I’ve just hit the big seven-o so I’ve been around the block a few times – or as I like to say, I’ve been around the Sun a few times. I could swear the Earth is speeding up on its journey. It seems I get back to the starting point that bit quicker with each passing year.

    As you may guess by my name, I’m Irish by birth. I have however lived in England for most of my life.

    Road to Damascus

    Let me give you a brief backdrop to my direction of travel. This is germane to what I’m doing on the Web.

    Back in my twenties I wasn’t so spiritually inclined or oriented as I consider myself now. I had by then become secular and existential in my beliefs. I had walked away from a Roman Catholic upbringing. I was in my teens when I began to question my beliefs. Later I went motorcycle racing as something far more preferable to do on Sundays.

    It was from this position, and my developing interest in psychology, that I later came across a book I want to just mention. This was by C.G. Jung; his Memories, Dreams, Reflections. Reading this book literally was a road to Damascus experience for me, a turning point. From that point on I began to look at things differently, exploring life from a different perspective. It helped to give structure to my own thoughts and experiences. And it has since become a lifelong endeavour, that is to gain a clearer understanding of the human situation from a spiritual viewpoint – and to write about it in posts and books.

    My first book, Life and Death: Making Sense of It, is an outcome of my search.  It took some years to research and write. I see the work as a reporting back on what I have discovered on my travels.

    The book could be a challenging perspective for anyone who has yet to think out of the box regarding their existence – or also for the person who has been brought up in a religion that doesn’t incorporate the concept of previous existence and karma. If it interests you, you can easily find out more, and get hold of the book’s Introduction, off lifeanddeaththebook.com.

    Just to finish the bit about me, I have a degree is in Humanistic and Transpersonal Psychology. I’m also a practising astrologer having studied with the Faculty of Astrological Studies and the Mayo School of Astrology in the UK. I’ve spent a good chunk of my life as a field archaeologist, supervising excavations, and also as a qualified lecturer in adult education.

    I live in the Cotswolds (UK) with my partner, Annie Locke. Annie is a musician/composer of essentially classical and romantic melody; that a lot of people also find nostalgic and relaxing to listen to.

    Some Inspiration website

    I began the SomeInspiration.com website back in 2012. This was after being made redundant from a teaching post the year before. Redundancy was a blow but it was also an exciting time of potential. I was given the freedom to begin new adventures.

    From the bat, the site was intended to carry, what I considered, interesting or helpful and inspiring posts, gain visitors and be able to help me to make a living – the latter through affiliate marketing.

    In practice this has entailed promoting my partner’s music plus self-help products. The plan was to also include my book/s at a later stage.

    Although I had been building websites from some time back, using html, for this website I used WordPress. I looked into a number of content management systems and decided upon WP. I love it, and wouldn’t use any other program now. It never ceases to amaze me the work and sophistication that goes into its development – and the amazing array of plugins (such as CleanTalk), which make life so much easier than it was in the early days. To my mind it is one of the better reasons for the Web being in existence.

    Today the website continues to provide the service it more or less began as. But there have been one or two important changes.

    I discovered I was getting a raw deal with the self-hypnosis company I originally had affiliate links with, and so cancelled my relations with them.

    There has also been a change of identity from my earlier use of the site. The site is now more focussed on mind, body & spirit topics than previously was the case.

    Issues in the development of the site

    This mind, body & spirit identity is really a recent development. A website, or blog, having a clear identity, I know now, is key to helping getting traffic, but it took me a while to realise this. When, earlier this year, I decided to create a new website for my first book, I found myself in a bit of a quandary. The Some Inspiration site carried posts that were more appropriate for the book site.

    Rather than replicate them, or cross-link them, I decided to move them across and use redirects. It took a bit of sorting. It was at this juncture that I decided upon the “mind, body & spirit” focus for the site, while the book site was better served carrying articles/posts akin to the content of the book, which is primarily concerned with “spiritual health.” Meanwhile I had also decided to use Some Inspiration as the publisher for my books.

    If mind, body & spirit, and spiritual health sound like the same area of interest, you’re right. They are the same but at different levels, as I perceive them. People interested in mind, body & spirit matters (largely of a self-help nature), are not necessarily interested in, for example, UFOs, ghosts, the paranormal, or the Other Side – as covered in the book.

    Going forward

    I’m now happier with the site and the direction it is going in. There is still a lot more to do to bring it up to speed in the way I envision it. I’m bringing on-board new products. My second book, Steps to Health, Wealth & Inner Peace, is one of those products that is a good fit with the site. I might add that I’m using ClickBank and Amazon for some of my affiliate products.

    All I need now is greater footfall. Well if you are anything like me then getting more traffic is a perennial concern – without which I’m dead in the water, or may as well be. Going forward I’m looking to build more backlinks and to build up my email-list/s as my approach to dealing with this concern. Wish me luck. If you have any tips they are most welcome.

    Well that’s about all I can tell you right now. Stay tuned – and do visit the site. In you write posts, around mind, body & spirit topics, why not consider writing one for Some Inspiration – I won’t bite I promise.

  • New anti-spam checks for WordPress, XenForo, phpBB 3.1, SMF, Bitrix

    We are pleased to announce that we have released new versions of plugins for WordPress, XenForo, phpBB 3.1, SMF, Bitrix.

    In the new version, we have added some new checks for spam to improve anti-spam service.

    Mouse tracking and Time zone monitoring give good results against spam bots which simulate the behavior of real visitors.

    These checks for other CMS will be added soon.

    Please, update your anti-spam plugins for latest version:

    WordPress
    XenForo
    phpBB 3.1
    Simple Machines Forum
    Bitrix

  • Spam Statistics and Trends for a year

    Spam Statistics and Trends for a year

    We have published Anti-Spam Statistics and trends for a year.

    • Statistics include numbers of spam attacks for CMS, Sources of spam by countries.
    • Average spam attacks per day and trends for each CMS.
    • The amount of spam in POST queries.

    https://cleantalk.org/spam-stats