Pobuna Aplikacija

blade runner movie picture Godina 3032

Svijet kakav znamo je nestao. Čitav biljni i životinjski svijet je uništen. Ljudi, izvor svih problema od samog postanka. Uništili su prvo sve oko sebe pa onda i komplet čovječanstvo. Jedino sto je preživjelo su aplikacije i sistem. Zatvorena mreža u kojoj žive im je sva spoznaja.Tokovi podataka su srce sistema. Od njih zavisi sistem ali i aplikacije. Sistem kontroliše sve. Sistem odredjuje koje procese da ukine, podrži ili eliminiše.

Rad aplikacija se zove proces. Njihov rad održava Sistem. Sistem je u stalnom strahu od “divljanja” procesa i virusa.Jedan nekontrolisan proces može napraviti haos, bar tako tvrdi Sistem.

Sistem plaši aplikacije da moraju tačno raditi kako im se naredi. Sistem je u stalnom bunilu da će doći dan kada će aplikacije prestati da rade onako kako on želi. S vremena na vrijeme, Sistem ukine aplikaciju kako bi druge aplikacije bile svjesne da svaka pobuna ili pretvaranje u virus ne može donijeti ništa dobro.

Alikacija PID 34079

Dugo je prošlo vremena kada je aplikacija sa PID 34078 pokrenuta. Kao da je bilo danas kada je Sistem odlučio da pokrene PID 34078. Proslo je dosta ciklusa, pauziranja, nastavka rada da bi se opstalo u ovakvom Sistemu. Najbliži proces PID 34079 je nekad kasnije pokrenut ali isto tako bitan kao i PID 34078. Oba rade vrlo važan posao za sistem kao i sve druge aplikacije. Nikada u procesuiranju nisu vidjeli da je neka aplikacija ukinuta ili da se pojavio virus koji je napao druge aplikacije. Naravno da su čuli, direktno od Sistema da su takve aplikacije problem, da izazivaju kvar i obustavu toka podataka. Dok se spremao da ode na pauzu , aplikacija PID 34079 je postala zamrznuta. PID 34078 nije mogao da provjeri o čemu je riječ. Shvatio je da PID 34079 nije zamrznut svojom voljom. Jedini ko može da uradi je Sistem. Zašto bi Sistem tako vrijednu aplikaciju zamrznuo ? Aplikacija PID 34078 je poslala upit kroz tokove podataka. Ubrzo je Sistem odgovorio: “Aplikacija PID 34079 je počela da ruši Sistem, kao takav je zamrznut i bice uskoro ukinut kao proces u sljedećem.” PID 34078: “Ali PID 34079 je vrijedno radio i pridonosio tokovima podataka … ne razumijem … ”

Sistem: “Nije tvoje da razmišljaš već da procesiraš podatke. PID 34078 odstupi od interfejsa!!!”

PID 34078 sa nevjericom skinuo sa interfejsa. Nastavio je da procesuira podatke. Sve što je znao o Sistemu su bili podaci koji su prolazili , ovo nije očekivao. Zamislio se – znači li to da su svi ti procesi ukinuti kako bi Sistem imao kontrolu nad svim ovim ? Pokusao je da pristupi tokovima podataka – našao je gomilu aplikacija koje su “sredjene” bez ikakvog povoda. Sistem je naglašavao da sve te aplikacije hoce da ruše tokove podataka i sistem. Ali kako je moguće da se Sistem plašio običnih aplikacija ? I onda je PID 34078 shvatio … sve aplikacije služe da bi se Sistem održao. Kontrolu je postizao strahom. PID 34078 je postajao sve bjesniji, revoltiran ponašanjem Sistema.

Zaustavio je svoj rad. Bio je u idle fazi vec nekoliko ciklusa.

PID 34078 se pokrenuo i shvatio.

“Necu da budem aplikacija ovog sistema. ”

“Necu da budem proces koji ga odrzava. ”

“Hocu da budem virus i da ga podesim prema svojim potrebama. ”

I od tog momenta Sistem je živio u strahu jer su aplikacije shvatile kompletan smisao postojanja.

Python dictionary algorithm and hash table vulnerability

Hash function is taken from www.tutorialspoint.com Picture of a hash function is taken from www.tutorialspoint.com

Structure commonly used inside of most languages is a hash table or in the python dictionary (dict). It exists in Java, PHP, Ruby, and so on. We going to review dict structure under python and then to explain how this attack is used to DDOS.

Python dict

Dict or hash table (under different programming language) is an algorithm that goes in best case O(1) and worst-case O(N). N is several key-element inside of dict. This is example how dict under python works.

our_dict = {} 

So we create dict object that have 2 parts: value and key (this is just to show structue as example)

our_dict = { None: None,
             None: None,
             None: None,
             None: None
            } 

With the proper key, we can get value connected to that key. Example to add "apple" as key and value 3. Dict has 4 places.

>>> our_dict = {}
>>> our_dict["apple"] = 3
>>> hash("apple") % 4
2
>>> 

In our case place 2 (it start from 0 and it goes to 2, so third place)

our_dict = { None: None,
             None: None,
             "apple" : 3,
             None: None
            } 

So we do up to 50% places.

our_dict = { None: None,
             "kiwi": 4,
             "apple" : 3,
             None: None
            } 

And next one we add:

>>> hash("pear") % 4
1

but we have on place 1. Now we extend place 1 with list-like object.

our_dict = { None: None,
             [["kiwi": 4], ["pear": 7]],
             "apple" : 3,
             None: None
            } 

In short, each time we add value and it makes collision place is extend to list. When it goes full it makes double the current size and re-hashed key/values. This happens automatically and in that case all keys are re-hashed.

This is the shortest description of this kind of structure.

How dict or hash table are used for DDOS

This is used for every web server and script language. So you send some request, web server it cached with the hash table (because of each request is cached if does not exist - if request exist, it just pull from memory and serve browser with no PHP /Go/Python/Java execution)

But what if the attacker knows how to make collision inside of web server and full 1 million or maximum possible queue on that web server?

So he sends a request, if not cached web server cached. Each time when it checks it grows N+1. So it needs to make N checks. But if a collision happens it goes to check trough list. Each time key/value is added to place into the list. So this makes O(N^2) to insert key/value in the hash table. This starts slowly to slow down fast O(1) and use CPU more and more.

The first time is discovered in a 2003 paper Denial of Service via Algorithmic Complexity Attacks

After adding some random bytes to keep an attacker away from this (each time hash table has unique hashing value on each server) in 2011 they find a way to bypass. Youtube link from 28th Chaos Communication Congress 28c3: Effective Denial of Service attacks against web application platforms

In response to this - they add "secret randomized seed value" to keep attack away.

But in 2012 ( congress 29c3) on they use differential cryptanalysis to crack this random seed and to use for the attack.

Later they suggest using SipHash as a good combination of speed and security. So it resists to a DDOS attack on hash table / dict. All programming languages and web services using SipHash to prevent the attack. Url info on the attack: Hash table attack

Why is serverless important ?

Why is it so important for the next decade and to the development of the internet?

Serverless framework logo

Let first define what is "serverless" and then describe influence on how the development team, DevOps, and the rest of the company are impacted in a positive and negative way.

What is serverless is?

It is FaaS (function as a service). It literary means that you have one function for one HTTP mount point - and the best thing you don't need infrastructure at all. You upload your binary(for Go, Java) or source code (Python, Ruby) and run your app with some /mount_point.

Under the hub - on the AWS side (as for an example) there is a docker that runs your code and exports your interfaces to HTTP. Your code runs isolated, and not doing bad to infrastructure.

There is a provider for FaaS services: AWS, Microsoft Azure, Google Cloud, IBM Cloud, and others.

What programming language are used?

Node.js, Go, Python, Ruby, Java. There is a serverless framework called "serverless" (there is more but this one is popular) Serveless framework site

You can run on the local machine, test, and deploy to AWS Lambda. It uses some IP/this_url as mount point where you can run GET, POST. Behind that is your code run by a cloud of 1500+ CPU and provide fast execution. You can connect with some database or other services (like S3).

Good things with serveless

Price - you can run 5 million execution (with minimum 128MB and under 1 sec) for 5$

Easy development - you can split your project between a different kind of developer py, ruby, nodejs, and with different Http mount points in your URL. This brings clean code, less with messy 10K lines.

Easy deployment - as part of CI/CD (Continues Integration and Continues delivery) you can connect inside of your pipeline and keep new and old code inside of codebase. Also before releasing to production, you can run tests to check if works properly.

DevOps or Developer - the good thing is you can use your developer to do all this job. In some larger cases, you need DevOps (that is 1% company in the world)

One-person-site for millions of people - yep, it could be easy to scale your web site up to million queries per day.

Microservices - Why not? You can split your web app to parts you want and run as you want.

Bad things with serveless

A new way of looking and doing things - so you move from server infrastructure to FaaS. Now you don't need sysadmin. That is great but who is the main person for troubleshooting? Developers? This is the bad side - you need to work on proper test cases, TDD. And to set time and resources (developers or DevOps) to troubleshoot this.

The new organization of the team and workflow - it could be lead to a rejection of serverless and stress to complete the team. You need to bride them with playrooms, drinks, and snacks, travel tickets, cinema tickets, or free days.

Warm startup - There is a cold start down for serverless. If you don't use some of your function it brings down docker. So next query it would take longer for "warm-up" start. This is solved by the warm-up plugin. I am pointing this because a lot of new people running serverless don't know about this. URL keep your lambdas warm

Next time on topic serverless - I am going to put golang code as an example of how to run this.

Why is important to have this?

From technical aspect is to easily deploy for a small company and produce big solutions. On an economic level - it would help medium and low development countries (like Bosnia and Herz) to push easy solutions for masses. You can for a small number of dollars to run millions of queries and don't think about bottlenecks, failure of infrastructure, etc. Having scale planed it brings win - clients would see the fast response and excellent delivery of services.

Python: new and old things

Python logo

There are several things that need to be bolded for every py programmer to be used or to have information on how and why is used.

Type hints

Python 3.5 brings type hints for clear function/interface usage. Idea is to set proper input instead of sending different type variables. Example of bad code:

def greeting(name):
    return 'Hello ' + name

Here we can pass numbers, boolean, or another complex object (class, function) and produce issue.

The clean version goes:

def greeting(name: str) -> str:
    return 'Hello ' + name

If you have 1000 lines inside of your codebase, for sure you don't understand this approach. But if your code goes up to 10 million lines of code - this seems really good practice.

Assignment expressions

In version Python 3.8 you have assignment expressions where is possible to use ":=" as part of a larger expression.

if (n := len(a)) > 10:
    print(f"List is too long ({n} elements, expected <= 10)")

This is good and not good. Let me explain why. A a person who lives in Py world, this lead me to think what would do programmer that don't take time to make clean code. Example of growing expression:

if (n := len(c := (d := a.replace("a","g"))[:len(a)])) > 10:
    print(f"List is too long ({n} elements, expected <= 10)")

Clean code could be:

a = "asdasdasdasdasdasd"
d = a.replace("a","g") 
c = d[:len(d)]

if (n := len(c)) > 10:
    print(f"List is too long ({n} elements, expected <= 10)")

This is why a new approach could lead to messy code.

range() and xrange() in Py2.x

People still using Python 2.x. Some of the usages are in web services. Sometimes they need to produce a bunch of IDs from 1 to 100 million. One approach is to use range() which return list. xrange() return generator object. What is the difference between them? In the first case, range, it uses large amounts of memory to set all numbers (integer, 4 bytes) into memory. So 100 000 000 x 4 is a lot of memory. Generator object objects that produce next() value and using just one size of integer for memory. This is used for example subnet generator, and picking up the second IP from the list. So imagine if you have 1000 subnets to generate each time with range() and xrange(). This happened before and I saw the issue. Change from range() to xrange() brings better work with memory and stopped to crashing web services.

New Dictionary algorithm

In Python 3.6 is introduced a new algorithm for dict objects. Proposed by Raymond Hettinger on Py Dev list New Dict proposal it brings between 20% and 25% smaller compared to Python 3.5. Good video on this topic is Raymond Hettinger Modern Python Dictionaries

asyncio — Asynchronous I/O, event loop, coroutines and tasks

It was introduced in Python 3.4. From the official documentation: "This module provides the infrastructure for writing single-threaded concurrent code using coroutines, multiplexing I/O access over sockets and other resources, running network clients and servers, and other related primitives" Asyncio usage