RFC2109 - HTTP State Management Mechanism

Network Working Group                                         D. Kristol
Request for Comments: 2109 Bell Laboratories, Lucent Technologies
Category: Standards Track L. Montulli
Netscape Communications
February 1997

HTTP State Management Mechanism

Status of this Memo

This document specifies an Internet standards track protocol for the
Internet community, and requests discussion and suggestions for
improvements. Please refer to the current edition of the "Internet
Official Protocol Standards" (STD 1) for the standardization state
and status of this protocol. Distribution of this memo is unlimited.

1. ABSTRACT

This document specifies a way to create a stateful session with HTTP
requests and responses. It describes two new headers, Cookie and
Set-Cookie, which carry state information between participating
origin servers and user agents. The method described here differs
from Netscape's Cookie proposal, but it can interoperate with
HTTP/1.0 user agents that use Netscape's method. (See the HISTORICAL
section.)

2. TERMINOLOGY

The terms user agent, client, server, proxy, and origin server have
the same meaning as in the HTTP/1.0 specification.

Fully-qualified host name (FQHN) means either the fully-qualified
domain name (FQDN) of a host (i.e., a completely specified domain
name ending in a top-level domain such as .com or .uk), or the
numeric Internet Protocol (IP) address of a host. The fully
qualified domain name is preferred; use of numeric IP addresses is
strongly discouraged.

The terms request-host and request-URI refer to the values the client
would send to the server as, respectively, the host (but not port)
and abs_path portions of the absoluteURI (http_URL) of the HTTP
request line. Note that request-host must be a FQHN.

Hosts names can be specified either as an IP address or a FQHN
string. Sometimes we compare one host name with another. Host A's
name domain-matches host B's if

* both host names are IP addresses and their host name strings match
exactly; or

* both host names are FQDN strings and their host name strings match
exactly; or

* A is a FQDN string and has the form NB, where N is a non-empty name
string, B has the form .B', and B' is a FQDN string. (So, x.y.com
domain-matches .y.com but not y.com.)

Note that domain-match is not a commutative operation: a.b.c.com
domain-matches .c.com, but not the reverse.

Because it was used in Netscape's original implementation of state
management, we will use the term cookie to refer to the state
information that passes between an origin server and user agent, and
that gets stored by the user agent.

3. STATE AND SESSIONS

This document describes a way to create stateful sessions with HTTP
requests and responses. Currently, HTTP servers respond to each
client request without relating that request to previous or
subsequent requests; the technique allows clients and servers that
wish to exchange state information to place HTTP requests and
responses within a larger context, which we term a "session". This
context might be used to create, for example, a "shopping cart", in
which user selections can be aggregated before purchase, or a
magazine browsing system, in which a user's previous reading affects
which offerings are presented.

There are, of course, many different potential contexts and thus many
different potential types of session. The designers' paradigm for
sessions created by the exchange of cookies has these key attributes:

1. Each session has a beginning and an end.

2. Each session is relatively short-lived.

3. Either the user agent or the origin server may terminate a
session.

4. The session is implicit in the exchange of state information.

4. OUTLINE

We outline here a way for an origin server to send state information
to the user agent, and for the user agent to return the state
information to the origin server. The goal is to have a minimal
impact on HTTP and user agents. Only origin servers that need to
maintain sessions would suffer any significant impact, and that
impact can largely be confined to Common Gateway Interface (CGI)
programs, unless the server provides more sophisticated state
management support. (See Implementation Considerations, below.)

4.1 Syntax: General

The two state management headers, Set-Cookie and Cookie, have common
syntactic properties involving attribute-value pairs. The following
grammar uses the notation, and tokens DIGIT (decimal digits) and
token (informally, a sequence of non-special, non-white space
characters) from the HTTP/1.1 specification [RFC 2068] to describe
their syntax.

av-pairs = av-pair *(";" av-pair)
av-pair = attr ["=" value] ; optional value
attr = token
value = word
word = token | quoted-string

Attributes (names) (attr) are case-insensitive. White space is
permitted between tokens. Note that while the above syntax
description shows value as optional, most attrs require them.

NOTE: The syntax above allows whitespace between the attribute and
the = sign.

4.2 Origin Server Role

4.2.1 General

The origin server initiates a session, if it so desires. (Note that
"session" here does not refer to a persistent network connection but
to a logical session created from HTTP requests and responses. The
presence or absence of a persistent connection should have no effect
on the use of cookie-derived sessions). To initiate a session, the
origin server returns an extra response header to the client, Set-
Cookie. (The details follow later.)

A user agent returns a Cookie request header (see below) to the
origin server if it chooses to continue a session. The origin server
may ignore it or use it to determine the current state of the

session. It may send back to the client a Set-Cookie response header
with the same or different information, or it may send no Set-Cookie
header at all. The origin server effectively ends a session by
sending the client a Set-Cookie header with Max-Age=0.

Servers may return a Set-Cookie response headers with any response.
User agents should send Cookie request headers, subject to other
rules detailed below, with every request.

An origin server may include multiple Set-Cookie headers in a
response. Note that an intervening gateway could fold multiple such
headers into a single header.

4.2.2 Set-Cookie Syntax

The syntax for the Set-Cookie response header is

set-cookie = "Set-Cookie:" cookies
cookies = 1#cookie
cookie = NAME "=" VALUE *(";" cookie-av)
NAME = attr
VALUE = value
cookie-av = "Comment" "=" value
| "Domain" "=" value
| "Max-Age" "=" value
| "Path" "=" value
| "Secure"
| "Version" "=" 1*DIGIT

Informally, the Set-Cookie response header comprises the token Set-
Cookie:, followed by a comma-separated list of one or more cookies.
Each cookie begins with a NAME=VALUE pair, followed by zero or more
semi-colon-separated attribute-value pairs. The syntax for
attribute-value pairs was shown earlier. The specific attributes and
the semantics of their values follows. The NAME=VALUE attribute-
value pair must come first in each cookie. The others, if present,
can occur in any order. If an attribute appears more than once in a
cookie, the behavior is undefined.

NAME=VALUE
Required. The name of the state information ("cookie") is NAME,
and its value is VALUE. NAMEs that begin with $ are reserved for
other uses and must not be used by applications.

The VALUE is opaque to the user agent and may be anything the
origin server chooses to send, possibly in a server-selected
printable ASCII encoding. "Opaque" implies that the content is of
interest and relevance only to the origin server. The content
may, in fact, be readable by anyone that examines the Set-Cookie
header.

Comment=comment
Optional. Because cookies can contain private information about a
user, the Cookie attribute allows an origin server to document its
intended use of a cookie. The user can inspect the information to
decide whether to initiate or continue a session with this cookie.

Domain=domain
Optional. The Domain attribute specifies the domain for which the
cookie is valid. An explicitly specified domain must always start
with a dot.

Max-Age=delta-seconds
Optional. The Max-Age attribute defines the lifetime of the
cookie, in seconds. The delta-seconds value is a decimal non-
negative integer. After delta-seconds seconds elapse, the client
should discard the cookie. A value of zero means the cookie
should be discarded immediately.

Path=path
Optional. The Path attribute specifies the subset of URLs to
which this cookie applies.

Secure
Optional. The Secure attribute (with no value) directs the user
agent to use only (unspecified) secure means to contact the origin
server whenever it sends back this cookie.

The user agent (possibly under the user's control) may determine
what level of security it considers appropriate for "secure"
cookies. The Secure attribute should be considered security
advice from the server to the user agent, indicating that it is in
the session's interest to protect the cookie contents.

Version=version
Required. The Version attribute, a decimal integer, identifies to
which version of the state management specification the cookie
conforms. For this specification, Version=1 applies.

4.2.3 Controlling Caching

An origin server must be cognizant of the effect of possible caching
of both the returned resource and the Set-Cookie header. Caching
"public" documents is desirable. For example, if the origin server
wants to use a public document such as a "front door" page as a
sentinel to indicate the beginning of a session for which a Set-
Cookie response header must be generated, the page should be stored
in caches "pre-expired" so that the origin server will see further
requests. "Private documents", for example those that contain
information strictly private to a session, should not be cached in
shared caches.

If the cookie is intended for use by a single user, the Set-cookie
header should not be cached. A Set-cookie header that is intended to
be shared by multiple users may be cached.

The origin server should send the following additional HTTP/1.1
response headers, depending on circumstances:

* To suppress caching of the Set-Cookie header: Cache-control: no-
cache="set-cookie".

and one of the following:

* To suppress caching of a private document in shared caches: Cache-
control: private.

* To allow caching of a document and require that it be validated
before returning it to the client: Cache-control: must-revalidate.

* To allow caching of a document, but to require that proxy caches
(not user agent caches) validate it before returning it to the
client: Cache-control: proxy-revalidate.

* To allow caching of a document and request that it be validated
before returning it to the client (by "pre-expiring" it):
Cache-control: max-age=0. Not all caches will revalidate the
document in every case.

HTTP/1.1 servers must send Expires: old-date (where old-date is a
date long in the past) on responses containing Set-Cookie response
headers unless they know for certain (by out of band means) that
there are no downsteam HTTP/1.0 proxies. HTTP/1.1 servers may send
other Cache-Control directives that permit caching by HTTP/1.1
proxies in addition to the Expires: old-date directive; the Cache-
Control directive will override the Expires: old-date for HTTP/1.1
proxies.

4.3 User Agent Role

4.3.1 Interpreting Set-Cookie

The user agent keeps separate track of state information that arrives
via Set-Cookie response headers from each origin server (as
distinguished by name or IP address and port). The user agent
applies these defaults for optional attributes that are missing:

VersionDefaults to "old cookie" behavior as originally specified by
Netscape. See the HISTORICAL section.

Domain Defaults to the request-host. (Note that there is no dot at
the beginning of request-host.)

Max-AgeThe default behavior is to discard the cookie when the user
agent exits.

Path Defaults to the path of the request URL that generated the
Set-Cookie response, up to, but not including, the
right-most /.

Secure If absent, the user agent may send the cookie over an
insecure channel.

4.3.2 Rejecting Cookies

To prevent possible security or privacy violations, a user agent
rejects a cookie (shall not store its information) if any of the
following is true:

* The value for the Path attribute is not a prefix of the request-
URI.

* The value for the Domain attribute contains no embedded dots or
does not start with a dot.

* The value for the request-host does not domain-match the Domain
attribute.

* The request-host is a FQDN (not IP address) and has the form HD,
where D is the value of the Domain attribute, and H is a string
that contains one or more dots.

Examples:

* A Set-Cookie from request-host y.x.foo.com for Domain=.foo.com
would be rejected, because H is y.x and contains a dot.

* A Set-Cookie from request-host x.foo.com for Domain=.foo.com would
be accepted.

* A Set-Cookie with Domain=.com or Domain=.com., will always be
rejected, because there is no embedded dot.

* A Set-Cookie with Domain=ajax.com will be rejected because the
value for Domain does not begin with a dot.

4.3.3 Cookie Management

If a user agent receives a Set-Cookie response header whose NAME is
the same as a pre-existing cookie, and whose Domain and Path
attribute values exactly (string) match those of a pre-existing
cookie, the new cookie supersedes the old. However, if the Set-
Cookie has a value for Max-Age of zero, the (old and new) cookie is
discarded. Otherwise cookies accumulate until they expire (resources
permitting), at which time they are discarded.

Because user agents have finite space in which to store cookies, they
may also discard older cookies to make space for newer ones, using,
for example, a least-recently-used algorithm, along with constraints
on the maximum number of cookies that each origin server may set.

If a Set-Cookie response header includes a Comment attribute, the
user agent should store that information in a human-readable form
with the cookie and should display the comment text as part of a
cookie inspection user interface.

User agents should allow the user to control cookie destruction. An
infrequently-used cookie may function as a "preferences file" for
network applications, and a user may wish to keep it even if it is
the least-recently-used cookie. One possible implementation would be
an interface that allows the permanent storage of a cookie through a
checkbox (or, conversely, its immediate destruction).

Privacy considerations dictate that the user have considerable
control over cookie management. The PRIVACY section contains more
information.

4.3.4 Sending Cookies to the Origin Server

When it sends a request to an origin server, the user agent sends a
Cookie request header to the origin server if it has cookies that are
applicable to the request, based on

* the request-host;

* the request-URI;

* the cookie's age.

The syntax for the header is:

cookie = "Cookie:" cookie-version
1*((";" | ",") cookie-value)
cookie-value = NAME "=" VALUE [";" path] [";" domain]
cookie-version = "$Version" "=" value
NAME = attr
VALUE = value
path = "$Path" "=" value
domain = "$Domain" "=" value

The value of the cookie-version attribute must be the value from the
Version attribute, if any, of the corresponding Set-Cookie response
header. Otherwise the value for cookie-version is 0. The value for
the path attribute must be the value from the Path attribute, if any,
of the corresponding Set-Cookie response header. Otherwise the
attribute should be omitted from the Cookie request header. The
value for the domain attribute must be the value from the Domain
attribute, if any, of the corresponding Set-Cookie response header.
Otherwise the attribute should be omitted from the Cookie request
header.

Note that there is no Comment attribute in the Cookie request header
corresponding to the one in the Set-Cookie response header. The user
agent does not return the comment information to the origin server.

The following rules apply to choosing applicable cookie-values from
among all the cookies the user agent has.

Domain Selection
The origin server's fully-qualified host name must domain-match
the Domain attribute of the cookie.

Path Selection
The Path attribute of the cookie must match a prefix of the
request-URI.

Max-Age Selection
Cookies that have expired should have been discarded and thus
are not forwarded to an origin server.

If multiple cookies satisfy the criteria above, they are ordered in
the Cookie header such that those with more specific Path attributes
precede those with less specific. Ordering with respect to other
attributes (e.g., Domain) is unspecified.

Note: For backward compatibility, the separator in the Cookie header
is semi-colon (;) everywhere. A server should also accept comma (,)
as the separator between cookie-values for future compatibility.

4.3.5 Sending Cookies in Unverifiable Transactions

Users must have control over sessions in order to ensure privacy.
(See PRIVACY section below.) To simplify implementation and to
prevent an additional layer of complexity where adequate safeguards
exist, however, this document distinguishes between transactions that
are verifiable and those that are unverifiable. A transaction is
verifiable if the user has the option to review the request-URI prior
to its use in the transaction. A transaction is unverifiable if the
user does not have that option. Unverifiable transactions typically
arise when a user agent automatically requests inlined or embedded
entities or when it resolves redirection (3xx) responses from an
origin server. Typically the origin transaction, the transaction
that the user initiates, is verifiable, and that transaction may
directly or indirectly induce the user agent to make unverifiable
transactions.

When it makes an unverifiable transaction, a user agent must enable a
session only if a cookie with a domain attribute D was sent or
received in its origin transaction, such that the host name in the
Request-URI of the unverifiable transaction domain-matches D.

This restriction prevents a malicious service author from using
unverifiable transactions to induce a user agent to start or continue
a session with a server in a different domain. The starting or
continuation of such sessions could be contrary to the privacy
expectations of the user, and could also be a security problem.

User agents may offer configurable options that allow the user agent,
or any autonomous programs that the user agent executes, to ignore
the above rule, so long as these override options default to "off".

Many current user agents already provide a review option that would
render many links verifiable. For instance, some user agents display
the URL that would be referenced for a particular link when the mouse
pointer is placed over that link. The user can therefore determine
whether to visit that site before causing the browser to do so.
(Though not implemented on current user agents, a similar technique
could be used for a button used to submit a form -- the user agent

could display the action to be taken if the user were to select that
button.) However, even this would not make all links verifiable; for
example, links to automatically loaded images would not normally be
subject to "mouse pointer" verification.

Many user agents also provide the option for a user to view the HTML
source of a document, or to save the source to an external file where
it can be viewed by another application. While such an option does
provide a crude review mechanism, some users might not consider it
acceptable for this purpose.

4.4 How an Origin Server Interprets the Cookie Header

A user agent returns much of the information in the Set-Cookie header
to the origin server when the Path attribute matches that of a new
request. When it receives a Cookie header, the origin server should
treat cookies with NAMEs whose prefix is $ specially, as an attribute
for the adjacent cookie. The value for such a NAME is to be
interpreted as applying to the lexically (left-to-right) most recent
cookie whose name does not have the $ prefix. If there is no
previous cookie, the value applies to the cookie mechanism as a
whole. For example, consider the cookie

Cookie: $Version="1"; Customer="WILE_E_COYOTE";
$Path="/acme"

$Version applies to the cookie mechanism as a whole (and gives the
version number for the cookie mechanism). $Path is an attribute
whose value (/acme) defines the Path attribute that was used when the
Customer cookie was defined in a Set-Cookie response header.

4.5 Caching Proxy Role

One reason for separating state information from both a URL and
document content is to facilitate the scaling that caching permits.
To support cookies, a caching proxy must obey these rules already in
the HTTP specification:

* Honor requests from the cache, if possible, based on cache validity
rules.

* Pass along a Cookie request header in any request that the proxy
must make of another server.

* Return the response to the client. Include any Set-Cookie response
header.

* Cache the received response subject to the control of the usual
headers, such as Expires, Cache-control: no-cache, and Cache-
control: private,

* Cache the Set-Cookie subject to the control of the usual header,
Cache-control: no-cache="set-cookie". (The Set-Cookie header
should usually not be cached.)

Proxies must not introduce Set-Cookie (Cookie) headers of their own
in proxy responses (requests).

5. EXAMPLES

5.1 Example 1

Most detail of request and response headers has been omitted. Assume
the user agent has no stored cookies.

1. User Agent -> Server

POST /acme/login HTTP/1.1
[form data]

User identifies self via a form.

2. Server -> User Agent

HTTP/1.1 200 OK
Set-Cookie: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"

Cookie reflects user's identity.

3. User Agent -> Server

POST /acme/pickitem HTTP/1.1
Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
[form data]

User selects an item for "shopping basket."

4. Server -> User Agent

HTTP/1.1 200 OK
Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";
Path="/acme"

Shopping basket contains an item.

5. User Agent -> Server

POST /acme/shipping HTTP/1.1
Cookie: $Version="1";
Customer="WILE_E_COYOTE"; $Path="/acme";
Part_Number="Rocket_Launcher_0001"; $Path="/acme"
[form data]

User selects shipping method from form.

6. Server -> User Agent

HTTP/1.1 200 OK
Set-Cookie: Shipping="FedEx"; Version="1"; Path="/acme"

New cookie reflects shipping method.

7. User Agent -> Server

POST /acme/process HTTP/1.1
Cookie: $Version="1";
Customer="WILE_E_COYOTE"; $Path="/acme";
Part_Number="Rocket_Launcher_0001"; $Path="/acme";
Shipping="FedEx"; $Path="/acme"
[form data]

User chooses to process order.

8. Server -> User Agent

HTTP/1.1 200 OK

Transaction is complete.

The user agent makes a series of requests on the origin server, after
each of which it receives a new cookie. All the cookies have the
same Path attribute and (default) domain. Because the request URLs
all have /acme as a prefix, and that matches the Path attribute, each
request contains all the cookies received so far.

5.2 Example 2

This example illustrates the effect of the Path attribute. All
detail of request and response headers has been omitted. Assume the
user agent has no stored cookies.

Imagine the user agent has received, in response to earlier requests,
the response headers

Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";
Path="/acme"

and

Set-Cookie: Part_Number="Riding_Rocket_0023"; Version="1";
Path="/acme/ammo"

A subsequent request by the user agent to the (same) server for URLs
of the form /acme/ammo/... would include the following request
header:

Cookie: $Version="1";
Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo";
Part_Number="Rocket_Launcher_0001"; $Path="/acme"

Note that the NAME=VALUE pair for the cookie with the more specific
Path attribute, /acme/ammo, comes before the one with the less
specific Path attribute, /acme. Further note that the same cookie
name appears more than once.

A subsequent request by the user agent to the (same) server for a URL
of the form /acme/parts/ would include the following request header:

Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; $Path="/acme"

Here, the second cookie's Path attribute /acme/ammo is not a prefix
of the request URL, /acme/parts/, so the cookie does not get
forwarded to the server.

6. IMPLEMENTATION CONSIDERATIONS

Here we speculate on likely or desirable details for an origin server
that implements state management.

6.1 Set-Cookie Content

An origin server's content should probably be divided into disjoint
application areas, some of which require the use of state
information. The application areas can be distinguished by their
request URLs. The Set-Cookie header can incorporate information
about the application areas by setting the Path attribute for each
one.

The session information can obviously be clear or encoded text that
describes state. However, if it grows too large, it can become
unwieldy. Therefore, an implementor might choose for the session
information to be a key to a server-side resource. Of course, using

a database creates some problems that this state management
specification was meant to avoid, namely:

1. keeping real state on the server side;

2. how and when to garbage-collect the database entry, in case the
user agent terminates the session by, for example, exiting.

6.2 Stateless Pages

Caching benefits the scalability of WWW. Therefore it is important
to reduce the number of documents that have state embedded in them
inherently. For example, if a shopping-basket-style application
always displays a user's current basket contents on each page, those
pages cannot be cached, because each user's basket's contents would
be different. On the other hand, if each page contains just a link
that allows the user to "Look at My Shopping Basket", the page can be
cached.

6.3 Implementation Limits

Practical user agent implementations have limits on the number and
size of cookies that they can store. In general, user agents' cookie
support should have no fixed limits. They should strive to store as
many frequently-used cookies as possible. Furthermore, general-use
user agents should provide each of the following minimum capabilities
individually, although not necessarily simultaneously:

* at least 300 cookies

* at least 4096 bytes per cookie (as measured by the size of the
characters that comprise the cookie non-terminal in the syntax
description of the Set-Cookie header)

* at least 20 cookies per unique host or domain name

User agents created for specific purposes or for limited-capacity
devices should provide at least 20 cookies of 4096 bytes, to ensure
that the user can interact with a session-based origin server.

The information in a Set-Cookie response header must be retained in
its entirety. If for some reason there is inadequate space to store
the cookie, it must be discarded, not truncated.

Applications should use as few and as small cookies as possible, and
they should cope gracefully with the loss of a cookie.

6.3.1 Denial of Service Attacks

User agents may choose to set an upper bound on the number of cookies
to be stored from a given host or domain name or on the size of the
cookie information. Otherwise a malicious server could attempt to
flood a user agent with many cookies, or large cookies, on successive
responses, which would force out cookies the user agent had received
from other servers. However, the minima specified above should still
be supported.

7. PRIVACY

7.1 User Agent Control

An origin server could create a Set-Cookie header to track the path
of a user through the server. Users may object to this behavior as
an intrusive accumulation of information, even if their identity is
not evident. (Identity might become evident if a user subsequently
fills out a form that contains identifying information.) This state
management specification therefore requires that a user agent give
the user control over such a possible intrusion, although the
interface through which the user is given this control is left
unspecified. However, the control mechanisms provided shall at least
allow the user

* to completely disable the sending and saving of cookies.

* to determine whether a stateful session is in progress.

* to control the saving of a cookie on the basis of the cookie's
Domain attribute.

Such control could be provided by, for example, mechanisms

* to notify the user when the user agent is about to send a cookie
to the origin server, offering the option not to begin a session.

* to display a visual indication that a stateful session is in
progress.

* to let the user decide which cookies, if any, should be saved
when the user concludes a window or user agent session.

* to let the user examine the contents of a cookie at any time.

A user agent usually begins execution with no remembered state
information. It should be possible to configure a user agent never
to send Cookie headers, in which case it can never sustain state with

an origin server. (The user agent would then behave like one that is
unaware of how to handle Set-Cookie response headers.)

When the user agent terminates execution, it should let the user
discard all state information. Alternatively, the user agent may ask
the user whether state information should be retained; the default
should be "no". If the user chooses to retain state information, it
would be restored the next time the user agent runs.

NOTE: User agents should probably be cautious about using files to
store cookies long-term. If a user runs more than one instance of
the user agent, the cookies could be commingled or otherwise messed
up.

7.2 Protocol Design

The restrictions on the value of the Domain attribute, and the rules
concerning unverifiable transactions, are meant to reduce the ways
that cookies can "leak" to the "wrong" site. The intent is to
restrict cookies to one, or a closely related set of hosts.
Therefore a request-host is limited as to what values it can set for
Domain. We consider it acceptable for hosts host1.foo.com and
host2.foo.com to share cookies, but not a.com and b.com.

Similarly, a server can only set a Path for cookies that are related
to the request-URI.

8. SECURITY CONSIDERATIONS

8.1 Clear Text

The information in the Set-Cookie and Cookie headers is unprotected.
Two consequences are:

1. Any sensitive information that is conveyed in them is exposed
to intruders.

2. A malicious intermediary could alter the headers as they travel
in either direction, with unpredictable results.

These facts imply that information of a personal and/or financial
nature should only be sent over a secure channel. For less sensitive
information, or when the content of the header is a database key, an
origin server should be vigilant to prevent a bad Cookie value from
causing failures.

8.2 Cookie Spoofing

Proper application design can avoid spoofing attacks from related
domains. Consider:

1. User agent makes request to victim.cracker.edu, gets back
cookie session_id="1234" and sets the default domain
victim.cracker.edu.

2. User agent makes request to spoof.cracker.edu, gets back
cookie session-id="1111", with Domain=".cracker.edu".

3. User agent makes request to victim.cracker.edu again, and
passes

Cookie: $Version="1";
session_id="1234";
session_id="1111"; $Domain=".cracker.edu"

The server at victim.cracker.edu should detect that the second
cookie was not one it originated by noticing that the Domain
attribute is not for itself and ignore it.

8.3 Unexpected Cookie Sharing

A user agent should make every attempt to prevent the sharing of
session information between hosts that are in different domains.
Embedded or inlined objects may cause particularly severe privacy
problems if they can be used to share cookies between disparate
hosts. For example, a malicious server could embed cookie
information for host a.com in a URI for a CGI on host b.com. User
agent implementors are strongly encouraged to prevent this sort of
exchange whenever possible.

9. OTHER, SIMILAR, PROPOSALS

Three other proposals have been made to accomplish similar goals.
This specification is an amalgam of Kristol's State-Info proposal and
Netscape's Cookie proposal.

Brian Behlendorf proposed a Session-ID header that would be user-
agent-initiated and could be used by an origin server to track
"clicktrails". It would not carry any origin-server-defined state,
however. Phillip Hallam-Baker has proposed another client-defined
session ID mechanism for similar purposes.

While both session IDs and cookies can provide a way to sustain
stateful sessions, their intended purpose is different, and,
consequently, the privacy requirements for them are different. A
user initiates session IDs to allow servers to track progress through
them, or to distinguish multiple users on a shared machine. Cookies
are server-initiated, so the cookie mechanism described here gives
users control over something that would otherwise take place without
the users' awareness. Furthermore, cookies convey rich, server-
selected information, whereas session IDs comprise user-selected,
simple information.

10. HISTORICAL

10.1 Compatibility With Netscape's Implementation

HTTP/1.0 clients and servers may use Set-Cookie and Cookie headers
that reflect Netscape's original cookie proposal. These notes cover
inter-operation between "old" and "new" cookies.

10.1.1 Extended Cookie Header

This proposal adds attribute-value pairs to the Cookie request header
in a compatible way. An "old" client that receives a "new" cookie
will ignore attributes it does not understand; it returns what it
does understand to the origin server. A "new" client always sends
cookies in the new form.

An "old" server that receives a "new" cookie will see what it thinks
are many cookies with names that begin with a $, and it will ignore
them. (The "old" server expects these cookies to be separated by
semi-colon, not comma.) A "new" server can detect cookies that have
passed through an "old" client, because they lack a $Version
attribute.

10.1.2 Expires and Max-Age

Netscape's original proposal defined an Expires header that took a
date value in a fixed-length variant format in place of Max-Age:

Wdy, DD-Mon-YY HH:MM:SS GMT

Note that the Expires date format contains embedded spaces, and that
"old" cookies did not have quotes around values. Clients that
implement to this specification should be aware of "old" cookies and
Expires.

10.1.3 Punctuation

In Netscape's original proposal, the values in attribute-value pairs
did not accept "-quoted strings. Origin servers should be cautious
about sending values that require quotes unless they know the
receiving user agent understands them (i.e., "new" cookies). A
("new") user agent should only use quotes around values in Cookie
headers when the cookie's version(s) is (are) all compliant with this
specification or later.

In Netscape's original proposal, no whitespace was permitted around
the = that separates attribute-value pairs. Therefore such
whitespace should be used with caution in new implementations.

10.2 Caching and HTTP/1.0

Some caches, such as those conforming to HTTP/1.0, will inevitably
cache the Set-Cookie header, because there was no mechanism to
suppress caching of headers prior to HTTP/1.1. This caching can lead
to security problems. Documents transmitted by an origin server
along with Set-Cookie headers will usually either be uncachable, or
will be "pre-expired". As long as caches obey instructions not to
cache documents (following Expires: <a date in the past> or Pragma:
no-cache (HTTP/1.0), or Cache-control: no-cache (HTTP/1.1))
uncachable documents present no problem. However, pre-expired
documents may be stored in caches. They require validation (a
conditional GET) on each new request, but some cache operators loosen
the rules for their caches, and sometimes serve expired documents
without first validating them. This combination of factors can lead
to cookies meant for one user later being sent to another user. The
Set-Cookie header is stored in the cache, and, although the document
is stale (expired), the cache returns the document in response to
later requests, including cached headers.

11. ACKNOWLEDGEMENTS

This document really represents the collective efforts of the
following people, in addition to the authors: Roy Fielding, Marc
Hedlund, Ted Hardie, Koen Holtman, Shel Kaphan, Rohit Khare.

12. AUTHORS' ADDRESSES

David M. Kristol
Bell Laboratories, Lucent Technologies
600 Mountain Ave. Room 2A-227
Murray Hill, NJ 07974

Phone: (908) 582-2250
Fax: (908) 582-5809
EMail: dmk@bell-labs.com

Lou Montulli
Netscape Communications Corp.
501 E. Middlefield Rd.
Mountain View, CA 94043

Phone: (415) 528-2600
EMail: montulli@netscape.com

Posted by 방글24

    Client Side State - HTTP Cookies



Original of this text is here(www.netscape.com/newsref/std/cookie_spec.html)

PERSISTENT CLIENT STATE
HTTP COOKIES

Preliminary Specification - Use with caution


    Introduction

Cookies are a general mechanism which server side connections (such as CGI scripts) can use to both store and retrieve information on the client side of the connection. The addition of a simple, persistent, client-side state significantly extends the capabilities of Web-based client/server applications.

    Overview

A server, when returning an HTTP object to a client, may also send a piece of state information which the client will store. Included in that state object is a description of the range of URLs for which that state is valid. Any future HTTP requests made by the client which fall in that range will include a transmittal of the current value of the state object from the client back to the server. The state object is called a cookie, for no compelling reason.

This simple mechanism provides a powerful new tool which enables a host of new types of applications to be written for web-based environments. Shopping applications can now store information about the currently selected items, for fee services can send back registration information and free the client from retyping a user-id on next connection, sites can store per-user preferences on the client, and have the client supply those preferences every time that site is connected to.

    Specification

A cookie is introduced to the client by including a Set-Cookie header as part of an HTTP response, typically this will be generated by a CGI script.

    Syntax of the Set-Cookie HTTP Response Header

This is the format a CGI script would use to add to the HTTP headers a new piece of data which is to be stored by the client for later retrieval.
Set-Cookie: NAME=VALUE; expires=DATE;
path=PATH; domain=DOMAIN_NAME; secure
NAME=VALUE
This string is a sequence of characters excluding semi-colon, comma and white space. If there is a need to place such data in the name or value, some encoding method such as URL style %XX encoding is recommended, though no encoding is defined or required.

This is the only required attribute on the Set-Cookie header.

expires=DATE
The expires attribute specifies a date string that defines the valid life time of that cookie. Once the expiration date has been reached, the cookie will no longer be stored or given out.

The date string is formatted as:

Wdy, DD-Mon-YYYY HH:MM:SS GMT
This is based on RFC 822, RFC 850, RFC 1036, and RFC 1123, with the variations that the only legal time zone is GMT and the separators between the elements of the date must be dashes.

expires is an optional attribute. If not specified, the cookie will expire when the user's session ends.

Note: There is a bug in Netscape Navigator version 1.1 and earlier. Only cookies whose path attribute is set explicitly to "/" will be properly saved between sessions if they have an expires attribute.

domain=DOMAIN_NAME
When searching the cookie list for valid cookies, a comparison of the domain attributes of the cookie is made with the Internet domain name of the host from which the URL will be fetched. If there is a tail match, then the cookie will go through path matching to see if it should be sent. "Tail matching" means that domain attribute is matched against the tail of the fully qualified domain name of the host. A domain attribute of "acme.com" would match host names "anvil.acme.com" as well as "shipping.crate.acme.com".

Only hosts within the specified domain can set a cookie for a domain and domains must have at least two (2) or three (3) periods in them to prevent domains of the form: ".com", ".edu", and "va.us". Any domain that fails within one of the seven special top level domains listed below only require two periods. Any other domain requires at least three. The seven special top level domains are: "COM", "EDU", "NET", "ORG", "GOV", "MIL", and "INT".

The default value of domain is the host name of the server which generated the cookie response.

path=PATH
The path attribute is used to specify the subset of URLs in a domain for which the cookie is valid. If a cookie has already passed domain matching, then the pathname component of the URL is compared with the path attribute, and if there is a match, the cookie is considered valid and is sent along with the URL request. The path "/foo" would match "/foobar" and "/foo/bar.html". The path "/" is the most general path.

If the path is not specified, it as assumed to be the same path as the document being described by the header which contains the cookie.

secure
If a cookie is marked secure, it will only be transmitted if the communications channel with the host is a secure one. Currently this means that secure cookies will only be sent to HTTPS (HTTP over SSL) servers.

If secure is not specified, a cookie is considered safe to be sent in the clear over unsecured channels.

    Syntax of the Cookie HTTP Request Header

When requesting a URL from an HTTP server, the browser will match the URL against all cookies and if any of them match, a line containing the name/value pairs of all matching cookies will be included in the HTTP request. Here is the format of that line:
Cookie: NAME1=OPAQUE_STRING1; NAME2=OPAQUE_STRING2 ...

    Additional Notes

  • Multiple Set-Cookie headers can be issued in a single server response.
  • Instances of the same path and name will overwrite each other, with the latest instance taking precedence. Instances of the same path but different names will add additional mappings.
  • Setting the path to a higher-level value does not override other more specific path mappings. If there are multiple matches for a given cookie name, but with separate paths, all the matching cookies will be sent. (See examples below.)
  • The expires header lets the client know when it is safe to purge the mapping but the client is not required to do so. A client may also delete a cookie before it's expiration date arrives if the number of cookies exceeds its internal limits.
  • When sending cookies to a server, all cookies with a more specific path mapping should be sent before cookies with less specific path mappings. For example, a cookie "name1=foo" with a path mapping of "/" should be sent after a cookie "name1=foo2" with a path mapping of "/bar" if they are both to be sent.
  • There are limitations on the number of cookies that a client can store at any one time. This is a specification of the minimum number of cookies that a client should be prepared to receive and store.
    • 300 total cookies
    • 4 kilobytes per cookie, where the name and the OPAQUE_STRING combine to form the 4 kilobyte limit.
    • 20 cookies per server or domain. (note that completely specified hosts and domains are treated as separate entities and have a 20 cookie limitation for each, not combined)
    Servers should not expect clients to be able to exceed these limits. When the 300 cookie limit or the 20 cookie per server limit is exceeded, clients should delete the least recently used cookie. When a cookie larger than 4 kilobytes is encountered the cookie should be trimmed to fit, but the name should remain intact as long as it is less than 4 kilobytes.
  • If a CGI script wishes to delete a cookie, it can do so by returning a cookie with the same name, and an expires time which is in the past. The path and name must match exactly in order for the expiring cookie to replace the valid cookie. This requirement makes it difficult for anyone but the originator of a cookie to delete a cookie.
  • When caching HTTP, as a proxy server might do, the Set-cookie response header should never be cached.
  • If a proxy server receives a response which contains a Set-cookie header, it should propagate the Set-cookie header to the client, regardless of whether the response was 304 (Not Modified) or 200 (OK).

    Similarly, if a client request contains a Cookie: header, it should be forwarded through a proxy, even if the conditional If-modified-since request is being made.

    Examples

Here are some sample exchanges which are designed to illustrate the use of cookies.

First Example transaction sequence:

Client requests a document, and receives in the response:
Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT
When client requests a URL in path "/" on this server, it sends:
Cookie: CUSTOMER=WILE_E_COYOTE
Client requests a document, and receives in the response:
Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
When client requests a URL in path "/" on this server, it sends:
Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
Client receives:
Set-Cookie: SHIPPING=FEDEX; path=/foo
When client requests a URL in path "/" on this server, it sends:
Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001
When client requests a URL in path "/foo" on this server, it sends:
Cookie: CUSTOMER=WILE_E_COYOTE; PART_NUMBER=ROCKET_LAUNCHER_0001; SHIPPING=FEDEX

Second Example transaction sequence:

Assume all mappings from above have been cleared.
Client receives:
Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/
When client requests a URL in path "/" on this server, it sends:
Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001
Client receives:
Set-Cookie: PART_NUMBER=RIDING_ROCKET_0023; path=/ammo
When client requests a URL in path "/ammo" on this server, it sends:
Cookie: PART_NUMBER=RIDING_ROCKET_0023; PART_NUMBER=ROCKET_LAUNCHER_0001
NOTE: There are two name/value pairs named "PART_NUMBER" due to the inheritance of the "/" mapping in addition to the "/ammo" mapping.

Corporate Sales: 415/937-2555; Personal Sales: 415/937-3777; Government Sales: 415/937-3678
If you have any questions, please visit Customer Service.

Copyright ⓒ 1997 Netscape Communications Corporation


Posted by 방글24
쿠키는 서버와 클라이언트 사이에 정보를 주고 받을 수 있는 통로인 동시에, 서버가 사용할 수 있는 유일한 로컬시스템(클라이언트) 자원입니다. 이러한 쿠키를 이용하면 방문자에게 좀 더 친밀한(?) 서비스를 제공할 수 있는 웹사이트를 구성할 수 있습니다.
하지만 쿠키가 로컬시스템에 저장된다는 것 때문에 혹시 나의 정보가 나도 모르게 외부로 유출되지 않는가 하는 걱정을 하게 만드는 것도 쿠키입니다.
여기서는 쿠키가 매우 유용한 도구라는 긍정적인 면에서 쿠키정보를 다루기 위한 클래스를 작성해 보려 합니다. 이 클래스는 세셔너에 포함된 세셔너핸들러 쿠키용과 비교해 볼 때 유사한 부분이 많이 있습니다. 그러나 쿠키만을 위해 제작되었기 때문에 소스 분석하기에는(이해하기에는) 훨씬 수월할 것입니다. 이 클래스는 쿠키를 요리하는 도구의 역할을 하기 때문에 이름을 쿠커(cooker)라고 정했습니다.
쿠키(cooker - class.cooker.php)를 이용하는 것이 보안상 여러가지 문제를 가지고 있음에도 불구하고 제가 쿠커를 작성하는 것은 쿠키가 세션과 같은 다른 방법보다는 이해하기가 쉽고 웹문서를 작성하기가 편하고 단순하다는 것입니다. 또한 서버자원이 아닌 방문자의 로컬시스템 하드디스크에 쿠키정보를 저장하게 되어 많은 방문자가 동시에 접속하는 웹사이트에서는 많은 장점을 가지게 됩니다. 그리고 보안에 조금만 주의를 기울인다면 아주 민감한 정보가 아닌 이상은 적용하는데 별 무리가 없다는 이유도 있습니다. 제 자신과 여러분에게도 한번쯤은 쿠키 사용법을 습득할 수 있는 기회가 될 수도 있겠지요.
쿠커란?
쿠키를 직접 관리해주는 클래스입니다. 클라이언트에서 날라온 쿠키값을 디코딩(암호 해독 과정 포함)하여 얻은 정보를 이용해 쿠키변수를 설정합니다. 이 과정에서 쿠키가 담고 있는 현재 상태를 얻을 수 있습니다. 새로운 쿠키를 생성할 때는 쿠키변수 정보를 인코딩(암호화 과정 포함)하여 이 정보를 클라이언트로 보내어 쿠키파일에 저장할 수 있도록 합니다. 인코딩 과정에서 쿠키변수 정보와 함께 클라이언트 IP 및 현재 시간을 함께 담아 보내게 되며 이러한 정보는 다음 페이지에서 쿠키를 디코딩하는 과정에서 추출되어 적절히 이용하게 됩니다. 클라이언트 IP는 보안을 고려할 때 필요한 정보이고 현재 시간은 쿠키의 유효기간을 결정하기 위한 정보로 사용됩니다.
< 쿠커의 역할 >
쿠키의 유효기간
쿠키의 유효기간은 우선 params() 메소드로 설정할 수 있습니다. params()에 의해 쿠키 생성할 때 설정된 유효기간은 웹브라우저에 의해 관리됩니다. params() 메소드에서 lifetime의 기본값은 0입니다. 따라서 브라우저가 살아있는 동안만 쿠키가 존재합니다. 브라우저를 종료하는 즉시 쿠키 정보도 같이 사라집니다.
서버에서 관리되는 쿠키의 유효기간이 별도로 존재합니다. 브라우저에서 관리되는 lifetime과 독립적으로 서버에서는 쿠키 생성 후 31536001초(1년)가 지나면 쿠커가 생성한 쿠키를 삭제하도록 되어있습니다. 이 값은 gc_maxlifetime() 메소드로 변경될 수 있습니다.
gc_maxlifetime() 함수로 유효기간을 설정하는 것은 쿠키를 처음 생성할 때 한번만 수행하면 됩니다. 따라서 여러페이지에 걸쳐 쿠커를 사용할 때는 처음 진입하는 페이지에서만 이 함수로 유효기간을 설정하면 됩니다. 다른 페이지에서는 이 함수를 사용하지 않더라도 이미 유효기간에 대한 정보가 쿠키 내에 포함되어 있으므로 자동으로 수행할 수 있습니다.
제공되는 메소드
메소드 버전 기능
start 0.0.1 쿠키파일로부터 쿠키정보를 전달받아 쿠키변수 설정
params 0.0.1 쿠키 설정 매개변수 획득/설정
gc_maxlifetime 0.0.2 서버상에서 확인하는 쿠키의 생존시간 획득/설정
name 0.0.1 쿠키파일에 저장될 쿠키명 획득/설정
get 0.0.1 쿠키변수값 획득
set 0.0.1 쿠키변수 등록 및 값 설정
isset2 0.0.2 쿠키변수 존재여부 확인
unset2 0.0.1 쿠키변수 삭제
write 0.0.1 쿠키변수에 기록된 쿠키정보를 쿠키파일에 저장
delete 0.0.1 쿠키변수 삭제, 쿠키파일의 쿠키삭제
메소드 사용법
int start(void)
클라이언트에서 전달된 쿠키를 받아 그 정보를 디코딩한 후 방문자 IP, 쿠키에 마지막으로 접근한 시간, 쿠키변수를 설정합니다. 그리고 쿠키와 PHP에 의해 자동으로 만들어지는 $HTTP_COOKIE_VARS["쿠키명"] 및 해당 전역변수를 삭제합니다. 따라서 이들 전역변수에 의해 쿠키값에 접근할 수 없습니다. 쿠키명은 디폴트로 "PHP_AUTH_DATA"로 지정되어 있습니다.
방문자 IP, 쿠키에 마지막으로 접근한 시간, 쿠키변수 정보를 통해 쿠키의 현재 상태를 파악해 그 값을 되돌려 줍니다. 마지막으로 현재 시간을 기준으로 쿠키파일의 쿠키를 업데이트합니다.
< start() 함수의 동작 >
반환되는 상태값을 보면 다음과 같습니다.
상태값 설명
0 등록된 쿠키변수가 존재함(정상적인 상태)
1 초기 상태(이전에 쿠키가 생성된 적이 없거나 브라우저가 쿠키를 받아들이지 않음)
2 쿠키가 만료되었음, 따라서 등록된 모든 쿠키변수가 삭제되었음
3 등록된 쿠키변수가 없음
4 앞서 쿠키를 생성한 방문자 IP와 현재 방문자 IP가 다름(이상한 사람임)
[code php;gutter:false] <?php

require "./cooker/class.cooker.php"; // 쿠키정보 클래스

$cooker = new Cooker;

$cooker->params(3600);
$status = $cooker->start();

switch ($status) {
case 0:
echo "이전 페이지에서 쿠키변수를 등록하셨군요.\n"";
echo "\n";
echo "USERID=".$cooker->get("USERID")."\n"";
echo "DATA=".$cooker->get("DATA")."\n"";
$cooker->delete();
echo "쿠키변수 및 쿠키파일의 쿠커정보를 지웠습니다.\n"";
echo "USERID=".$cooker->get("USERID")."\n"";
echo "DATA=".$cooker->get("DATA")."\n"";
break;
case 1:
$data = "처음으로 구원진 쿠키";
$cooker->set("USERID", "hwooky");
$cooker->set("DATA", $data);
$cooker->write();
echo "이전에 쿠키가 생성된 적이 없거나"
." 브라우저가 쿠키를 받아들이지 않습니다.\n"";
echo "\n";
echo "USERID=hwooky\n"";
echo "DATA=$data\n"";
echo "새로운 쿠키를 구웠습니다.\n"";
break;
case 2:
$data = "쿠키가 만료되었습니다.";
break;
case 3:
echo "등록된 쿠키변수가 없습니다.\n"";
break;
case 4:
echo "어떻게 들어오셨어요???\n"";
break;
}

echo "<A href=$PHP_SELF?id=$id>다시실행</A>";

?> [/code]
쿠커 내부에서 기본으로 설정된 유효기간은 24분(1440초)입니다. 이것은 세션함수에서의 유효기간 기본값과 같습니다.
void params(int lifetime [, string path [, string domain]])
PHP4 세션함수에서 session_set_cookie_params() 함수와 같이 쿠키를 생성할 때 필요한 유효기간, 유효경로, 유효도메인을 설정하는데 사용되는 함수입니다. 이 함수는 반드시 start() 함수보다 앞서 수행하여야 합니다. 각 매개변수에 대한 자세한 설명을 앞장("쿠키 규격") 및 PHP4 메뉴얼 세션함수를 참조바랍니다.
[code php;gutter:false] $cooker->params(3600, "/phpclass/exam/cooker/", ".phpclass.com"); [/code]
첫번째 매개변수 lifetime는 쿠키가 생존하는 시간을 초로 나타냅니다. 3600초라고 지정하면 쿠키를 생성한 후 1시간이 지나면 쿠키는 더 이상 유효하지 않습니다. 이 값의 디폴트 값은 0이며 이 경우의 쿠키는 사용자가 브라우저를 종료할 때까지만 존재합니다.
두번째 매개변수 path는 유효경로를 지정합니다. 특정 디렉토리에서만 이용할 필요가 있는 쿠키를 생성할 때 유효경로를 지정합니다. 위와 같이 "/phpclass/exam/cooker/"라고 지정하면 "http://www.phpclass.com/phpclass/exam/cooker/"의 디렉토리 및 그 하위디렉토리에 있는 웹문서만 사용할 수 있는 쿠키를 생성합니다. 다른 곳에 있는 웹문서는 이 쿠키를 받을 수 없습니다. 디폴트 값은 "/"이며 이 경우의 쿠키는 서버의 모든 디렉토리에서 유효합니다.
세번째 매개변수 domain은 쿠키의 유효도메인을 지정합니다. 위와 같이 ".phpclass.com"이라고 지정하면 www.phpclass.com, ftp.phpclass.com 등 도메인의 뒷부분이 일치하는 웹서버로만 쿠키가 전달됩니다. 디폴트 값은 ""이며 이 경우의 쿠키는 쿠키를 생성한 서버의 도메인으로 자동 지정됩니다.
array params()
PHP4 세션함수에서 session_get_cookie_params() 함수와 같은 역할을 수행합니다. 즉 쿠키를 생성할 때 필요한 유효기간, 유효경로, 유효도메인의 현재 설정값을 되돌려 줍니다.
[code php;gutter:false] $params = $cooker->params();
echo "유효기간=".$params["lifetime"]."\n""
echo "유효경로=".$params["path"]."\n""
echo "유효도메인=".$params["domain"]."\n"" [/code]
void gc_maxlifetime(int lifetime), int gc_maxlifetime(void)
위에 있는 params() 함수가 클라이언트에 생성하게 되는 쿠키의 유효기간을 설정하는 것이라면 gc_maxlifetime() 함수는 서버에서 쿠키의 유효기간을 확인할 수 있도록 그 시간을 설정하거나 획득하기 위한 함수입니다.
[code php;gutter:false] $cooker = new Cooker;
$cooker->params(0); //클라이언트에서의 쿠키지속시간
$cooker->gc_maxlifetime(1440); //서버에서의 쿠키지속시간(초단위/24분)
$cooker->start(); [/code]
위와 같은 경우 params()에서 lifetime을 0으로 설정하였기 때문에 클라이언트에서의 쿠키지속시간은 브라우저가 살아있는 한 계속 쿠키는 존재합니다. 그러나 쿠키가 생성된 후 24분이 지나면 서버에서 gc_maxlifetime(1440)에 의해 쿠키정보를 임의로 삭제하게 됩니다. 이러한 기능은 시간에 의한 자동로그아웃을 구현할 때 유용하게 사용될 수 있을 것입니다.
params()와 gc_maxlifetime() 함수에서 설정할 때는 모두 start() 함수 전에 수행하여야 합니다.
string name([string newname])
쿠커에서 사용되는 쿠키명(cookie name)을 얻거나 새로운 쿠키명으로 설정할 때 사용할 수 있습니다. 새로운 쿠키명을 설정할 때는 반드시 start() 함수보다 앞서 수행하여야 합니다. 쿠커는 기본적으로 쿠키명을 "PHP_AUTH_DATA"로 설정되어 있습니다. 보안을 위해 주기적으로 변경해주는 것이 바람직합니다.
[code php;gutter:false] $cooker = new Cooker;
$cooker->name("NEW_COOKIE_NAME");
$cooker->start();
.
.
. [/code]
array get(void)
등록된 모든 쿠키변수에 대한 정보를 되돌려줍니다. 정확한 정보를 얻기 위해서는 start() 함수를 먼저 수행하여야 합니다.
[code php;gutter:false] $list = $cooker->get();
if (is_array($list))
while(list($name,$value)=each($list))
echo "\$list[$name]=$value\n""; [/code]
string get(string name)
쿠키변수명을 입력 매개변수로 지정하면 해당 쿠키변수명에 대한 값을 되돌려 줍니다.
[code php;gutter:false] $userid = $cooker->get("USERID"); [/code]
void set(string name [, string value])
쿠키변수를 등록시켜주며 동시에 그 값을 설정합니다. 값을 지정하지 않으면 널문자열로 초기화합니다.
[code php;gutter:false] $cooker->set("USERID", "hwooky"); [/code]
bool isset2(string name)
등록된 쿠키변수가 존재하는지 확인합니다. 존재하면 true, 아니면 false를 반환합니다. 쿠키변수의 값이 null이더라도 존재한다면 true를 반환합니다.
[code php;gutter:false] if ($cooker->isset2("USERID"))
echo "쿠키변수 USERID가 존재하네요.\n""; [/code]
void unset2([string name])
등록된 쿠키변수를 삭제합니다. 입력 매개변수를 지정하지 않으면 모든 쿠키변수를 삭제합니다.
[code php;gutter:false] $cooker->unset2("USERID"); [/code]
쿠키변수를 삭제해 주는 함수의 함수명은 unset2입니다. 메소드명을 unset으로하여 함수를 정의하면 에러(Parse error)가 발생하여 할 수 없이 unset2로 명명하였습니다. 클래스 내에서 정의된 메소드명이라 내장함수 unset와 전혀 관련이 없는데도 에러가 나는 것을 보면 PHP의 버그가 아니면 unset() 함수가 다른 함수와 달리 PHP 내에서 특수하게 처리되는 것 같습니다. 이와같이 메소드명으로 사용할 수 없는 함수명으로는 unset 외에도 empty, isset 입니다. 모두 변수 처리 관련 함수들입니다.
void write(void)
등록된 쿠키변수와 기타 쿠키파일에 저장할 정보를 인코딩(암호화 포함)하여 쿠키파일에 저장합니다. start() 함수를 먼저 수행하여야 하며, 또한 내부적으로 PHP header() 함수를 사용하기 때문에 브라우저로 출력하는 문자가 발생하기 전에 수행하여야 합니다.
[code php;gutter:false] $cooker->write(); [/code]
void delete()
쿠키변수를 모두 삭제한 후 쿠키파일에서 쿠커가 사용하는 쿠키를 삭제합니다. write() 함수와는 달리 응답헤더 정보와 관계없이 수행합니다. 왜냐하면 쿠키를 삭제하기 위해 PHP header() 함수를 사용하지 않으며 자바스크립트의 document.cookie 객체를 이용합니다. 로그아웃과 같은 기능을 수행할 때 요긴하게 사용될 수 있을 것입니다. 없어도 로그아웃할 수는 있겠지만 보다 편하게 하기 위해 작성되었습니다.
[code php;gutter:false] $cookie->delete(); [/code]
데이터 암호화 클래스(class.crypto.php)
보안에 취약한 쿠키의 단점을 다소나마 보완하기 위해 쿠키값을 암호화하는데 활용할 수 있는 클래스입니다. 이 클래스는 제가 작성한 것이 아니며 hansanderson 라는 분이 작성하여 공개한 것을 포함시켰을 뿐입니다. 쿠키를 아무리 암호화한다고 해도 그 알고리즘이 노출된다면 본래의 목적이 반감될 수 밖에 없다는 것을 인식하시고 이 부분은 직접 작성할 것을 고려해 보시는 것이 좋을 듯합니다. 따라서 이 클래스는 참고용으로 첨부되어 있을 뿐입니다. 이 클래스에서 정의된 메소드는 쿠커(class.cooker.php)에서 사용하게 됩니다. 그러나 실제로 쿠커 내용을 보면 아시겠지만 데이터 암호화 클래스에 있는 메소드를 전혀 이용하지 않고 있습니다. 동일한 메소드를 쿠커 내에서 더미함수로 정의하여 사용하고 있습니다. 따라서 현재의 쿠커를 이용하더라도 쿠키의 암호화는 수행되지 않습니다. 이것은 여러분의 몪으로 남겨 놓겠습니다. 아래는 데이터 암호화 클래스(class.crypto.php)를 공개한 분에 대한 개인신상입니다.
AUTHOR hansanderson
HOME www.hansanderson.com/php/crypto/
EMAIL corporation@hansanderson.com
쿠커를 이용한 실험 예제
메뉴 "회원인증정보 >> 장바구니 클래스"에 있는 예제를 실험 대상으로 하였습니다. 자세한 것은 "장바구니 클래스"를 참조바랍니다.

Posted by 방글24
document.cookie 객체의 구조
자바스크립트에서는 document.cookie 객체를 통해 쿠키에 접근할 수 있습니다. 이 객체는 대입연산자를 통해 새로운 값을 내부 쿠키 리스트에 추가할 수 있습니다.
[code javascript;gutter:false] document.cookie = "ID=123456789";
document.cookie = "PW=abcdefghi"; [/code]
위와 같은 자바스크립트를 수행하면 일반적인 대입문처럼 쿠키명 ID가 없어지는 것이 아니라 내부 쿠키 리스트에 ID라는 쿠키와 PW라는 쿠키가 추가될 것입니다. 만약 쿠키명이 일치하는 것이 내부 쿠키 리스트에 있었다면 새로운 값으로 대치될 것입니다.
이미 생성되어 있는 쿠키를 참조하려면 document.cookie 객체를 문자열처럼 다루면 됩니다. 이 문자열은 쿠키명과 쿠키값으로 구성되어 있습니다. 각 쿠키명과 쿠키값은 등호(=)로 구분되어 있고, 각각의 쿠키는 세미콜론(;)으로 구분되어 있습니다. 위와 같이 쿠키가 생성되었을 때 document.cookie 객체를 참조하면 "ID=123456789;PW=abcdefghi"라는 문자열을 얻을 수 있습니다. 이 문자열을 가지고 문자열 메소드인 indexOf() 또는 substring() 함수를 이용하면 각 쿠키에 대한 정보를 분리할 수 있을 것입니다. 이러한 예는 아래에 있는 사용자 정의 함수 getCookie()를 참조하기 바랍니다.
PHP에서와 마찬가지로 유효한 도메인과 유효한 경로에서 만들어 낸 쿠키 정보만이 document.cookie을 통해서 볼 수 있습니다.
document.cookie 객체를 직접 사용할 수도 있지만, 대부분 아래와 같이 미리 정의된 함수 setCookie(), getCookie(), delCookie()를 통해 쿠키를 다루게 됩니다.
쿠키 설정하기
PHP의 setcookie() 함수와는 달리 expires(유효기간) 매개변수의 단위는 천분의 일초단위로 설정합니다. secure가 다소 다르기는 하지만 다른 매개변수는 PHP와 별다르지 않습니다. 저장된 쿠키 정보를 보면 문자열 소스 차원에서 PHP에서 다룰 때와 동일하지 않습니다. 왜냐하면 PHP에서 인코딩/디코딩하는 방식과 자바스크립트에서 인코딩/디코딩하는 방식이 다르기 때문입니다. 따라서 양쪽의 함수를 혼용하여 사용하는데는 문제가 있으니 주의하기 바랍니다. 여기에 정의된 setCookie() 함수는 "Designing Dynamic Web Pages with JavaScript"의 저자 Nick Heinle의 작품을 변형시킨 것입니다. 본래의 함수는 서적을 참조하시기 바랍니다. 이 원서에 대한 번역서는 "자바스크립트로 다이나믹 웹페이지 디자인하기"라는 제목으로 나와 있습니다.
[code javascript;gutter:false] function setCookie(name, value, expires, path, domain, secure) {
secure = (secure == null) ? false : secure;
var exp = new Date();
exp.setTime(expires);
document.cookie = name + "=" + escape(value)
+ ((expires == null) ? "" : ("; expires=" + exp.toGMTString()))
+ ((path == null) ? "" : ("; path=" + path))
+ ((domain == null) ? "" : ("; doamin=" + domain))
+ ((secure == true) ? "; secure" : "");
} [/code]
예를 들어 아래와 같이 각 매개변수를 지정할 수 있으며, 이 때 유효기간은 1시간이 됩니다.
[code javascript;gutter:false] setCookie(
"mycookie", // 쿠키명
"cookie_value", // 쿠키값
exp.getTime()+1000*3600, // 유효 기간
"/exam", // 유효 디렉토리
".phpclass.com" // 유효 도메인
); [/code]
쿠키 정보 읽어오기
쿠키명과 값은 document.cookie 객체에 통해 참조될 수 있습니다. 자바스크립트가 저장하는 쿠키의 형태는 아래와 같으며 각각의 name=value 쌍은 세리콜론과 공백으로 구분되어지고 제일 마지막 값에는 세미콜론이 없습니다.
[code javascript;gutter:false] name1=value1; name2=value2; name3=value3 [/code]
쿠키의 값을 좀 더 쉽게 얻기 위해 다음과 같이 getCookie() 함수를 정의하여 사용합니다. 이 함수는 Nick Heinle의 작품을 그대로 가져왔습니다.
[code javascript;gutter:false] // Heinle's function for retrieving a cookie.
function getCookie(name) {
var cname = name + "=";
var dc = document.cookie;
if (dc.length > 0) {
begin = dc.indexOf(cname);
if (begin != -1) {
begin += cname.length;
end = dc.indexOf(";", begin);
if (end == -1)
end = dc.length;
return unescape(dc.substring(begin, end));
}
}
return null;
} [/code]
이 함수는 단지 쿠키명만 지정하여 주면 document.cookie 객체를 검사하여 해당 쿠키의 값을 되돌려 줍니다. 저장된 쿠키가 없는 경우에는 null 값을 되돌려 줍니다.
[code javascript;gutter:false] value = getCookie ("mycookie"); [/code]
쿠키 삭제하기
마지막으로 쿠키를 삭제할 수 있는 함수 delCookie()를 살펴보겠습니다. 이 함수는 쿠키 센추럴(www.cookiecentral.com)에 있는 Dorcht의 함수를 그대로 가져왔습니다.
[code javascript;gutter:false] function delCookie (name, path, domain) {
if (getCookie(name)) {
document.cookie = name + "="
+ ((path == null) ? "" : "; path=" + path)
+ ((domain == null) ? "" : "; domain=" + domain)
+ "; expires=Thu, 01-Jan-70 00:00:01 GMT";
}
} [/code]
delCookie() 함수는 쿠키 파일에서 쿠키를 삭제하기 위해 사용되는 함수이다. delCookie() 함수를 사용하기 위해서는 보통 쿠키명만 넘겨주면 된다. 그러나 setCookie() 함수에서 쿠키를 구울 때 path와 domain을 지정하였으면, delCookie() 함수로 지울 때도 동일할 path와 domain을 분명히 지정해 주어야 합니다. 예를 들어, "mycookie" 쿠키에 대한 정보는 다음과 같이 지울 수 있습니다.
[code javascript;gutter:false] delCookie("mycookie", "/exam", ".phpclass.com"); [/code]
구두점 인코딩/디코딩
브라우저가 등호(=)와 세미콜론(;)을 각 쿠키를 분리시키는 구분자로 사용하기 때문에, 이것들은 자신이 저장하는 텍스트안에 넣을 수가 없습니다. 이러한 특수 코드를 쿠키값에 저장하려면 document.cookie 객체에 문자열을 넘기기 전에 escape()를 사용하여 인코딩해야 하고, unescape()를 사용하여 복구하여야 합니다.
escape() 함수
일반문자를 ASCII 형식(URL 형식; 폼에서 보내어진 %가 붙은 문자) 문자로 변환합니다. 예를 들어 아래와 같이 "ASCII &? 문자"라는 문자열을 escape() 함수로 넘겨주면 "ASCII%20%26%3F%20%uBB38%uC790"라는 문자열을 되돌려 받습니다.
[code javascript;gutter:false] var encode = escape("ASCII &? 문자"); [/code]
unescape() 함수
ASCII 형식(URL 형식) 문자를 일반문자로 변환합니다. 예를 들어 아래와 같이 "ASCII%20%26%3F%20%uBB38%uC790"라는 문자열을 unescape() 함수로 넘겨주면 "ASCII &? 문자"라는 문자열을 되돌려 받습니다.
[code javascript;gutter:false] var decode = unescape("ASCII%20%26%3F%20%uBB38%uC790"); [/code]

'phpsource > 캐시&세션&쿠키' 카테고리의 다른 글

넷스케이프의 쿠키에 관한 예비 규격서(복사본)  (0) 2001.02.21
{쿠커}9.쿠커  (0) 2001.02.20
{쿠커}7.setcookie() 함수  (0) 2001.02.20
{쿠커}6.쿠키 다루기  (0) 2001.02.20
{쿠커}5.쿠키 규격  (0) 2001.02.20
Posted by 방글24
PHP에서의 쿠키
PHP가 거의 완벽하게 쿠키를 지원하기 때문에 쿠키를 이용하기 위해 이해하기 어려운 요구헤더나 응답헤더를 이해할 필요가 없습니다. 쿠키를 생성할 때는 setcookie() 함수를 사용합니다. 쿠키를 생성할 때 필요로 하는 옵션들 - 유효기간, 유효경로, 유효도메인, 보안설정 - 은 setcookie() 함수의 매개변수로 전달하면 됩니다. PHP 내에서 쿠키를 읽는 것은 변수를 액세스하는 것처럼 간단합니다. PHP 스크립트를 시작할 때 쿠키들은 자동적으로 전역변수로 사용되도록 만들어집니다. 예를 들어, 쿠키명이 "ID"이고 쿠키값이 "123456789"라면 쿠키명 "ID"에 해당하는 전역변수 $ID에 "123456789"라는 값이 저장되어 있을 것입니다. 때에 따라서는 $ID라는 전역변수대신에 $HTTP_COOKIE_VARS["ID"]라는 전역배열변수를 가지고 다룰 수 있습니다.
쿠키 설정하기
PHP에서는 setcookie() 함수를 이용하여 쿠키를 설정할 수 있습니다. PHP에서 쿠키를 생성하는 함수 setcookie()의 정의는 다음과 같으며, 이 중에 name를 제외한 나머지 매개변수는 모두 생략할 수 있습니다.
int setcookie(string name, string [value],
                                      int [expire],
                                      string [path],
                                      string [domain],
                                      int [secure]);
생략할 수 있는 매개변수에 대한 기본값은 빈문자열(value, path, domain)이거나 0(expire, secure)입니다. 예를 들어, 만약 expire와 path는 기본값을 사용하고 domain만 새로이 지정하고자 한다면 다음과 같이 사용할 수 있습니다.
[code php;gutter:false] setcookie("name", "value", 0, "", ".phpclass.com"); [/code]
구분 매개변수명 기본값 동작
쿠키의 유효기간 expires 0 사용자가 브라우저를 종료할 때 쿠키가 없어짐
쿠키의 유효 디렉토리 path 웹문서 경로 웹문서가 존재하는 디렉토리
쿠키의 유효 도메인 domain 지정안함 쿠키를 설정한 서버의 도메인
쿠키의 보안 secure 지정안함 Disabled
name & value
첫 번째 매개변수 name은 설정할 쿠키명이고 value는 그 쿠키에 저장될 이름입니다. 자세한 것은 앞장 "쿠키 규격"을 참조바랍니다.
유효기간 설정하기
세 번째 매개변수 expire는 쿠키 유효기간을 설정하는 함수이며, 정수형으로서 표준 유닉스 시간을 그 값으로 갖습니다. 유효기간은 반드시 타임스탬프(1970년 1월 1일 이후 시간을 초로 표시)로 지정됩니다. 이 타임스탬프는 PHP에서 time()과 mktime() 함수들을 사용하여 계산할 수 있습니다. time() 함수는 현재 시간을 타임스탬프로 리턴하며, mktime() 함수는 사람들에게 익숙한 형식의 날짜(예를 들어, Tue, 06 Feb 2001 12:57:21 GMT)를 타임스탬프로 변환해 줍니다. time() 함수와 mktime() 함수에 의해 계산된 시간은 웹서버 시간에 따라 계산되는데 반하여 쿠키의 유효기간은 웹서버가 아닌 클라이언트 시스템 상에서의 시간이며, 따라서 웹서버와 서로 다른 시간대에 있을 수 있습니다. 기본값인 0은 오직 현재 방문자의 브라우저 세션을 위해서 설정되며, 방문자가 브라우저를 닫으면 만료됩니다. 브라우저를 종료하더라도 계속 쿠키가 존재하기 위해서는 유효기간을 명시하여야 합니다.
[code php;gutter:false] // 3600초(1시간) 이후에 만료된다.
setcookie("mycookie", $value, time()+3600);

// 2002년 1월 1일에 만료된다.
setcookie("mycookie", $value, mktime(0,0,0,1,1,2002));

// 2020년 5월 12일 오후 6:30분에 만료된다.
setcookie("mycookie", $value, mktime(18,30,0,5,12,2020)); [/code]
이와 같이 유효기간을 지정하게 되면 브라우저를 종료한 뒤 다시 실행하더라도 그대로 보존되며, 지정된 시간이 되면 자동적으로 그 쿠키를 제거할 것입니다.
유효경로 지정하기
이 매개변수를 생략하는 경우에는 setcookie() 함수를 호출한 웹문서가 있는 디렉토리와 이 디렉토리의 하위 디렉토리에서만 쿠키값을 참조할 수 있게 됩니다. 따라서 PHP4 세션함수에서 사용되는 쿠키와 같이 모든 서버상의 모든 디렉토리에서 유효한 쿠키를 사용하려면 path 매개변수의 값으로 루트 디렉토리를 설정하여야 합니다. 즉, 세션함수에서의 쿠키는 "/"가 기본값이지만 setcookie() 함수에서의 기본값은 현재 디렉토리가 됩니다.
[code php;gutter:false] setcookie("mycookie", "cookie_value", 0, "/"); [/code]
"관련서적(?)"을 보다보면 이 부분에서 다소 상이하다는 것을 알 수 있습니다. 관련서적에는 기본 동작이 "/"로 서버상의 모든 디렉토리가 유효하다고 되어 있습니다. 그러나 이는 앞의쿠키 규격에서 보았듯이 HTTP 응답헤더 Set-Cookie에 유효경로를 지정하지 않으면 웹문서가 존재하는 디렉토리 및 그 하위 디렉토리에서만 유효한 쿠키가 만들어지게 됩니다. 관련서적 저자는 세션함수와 혼동하지 않았나 생각합니다. 세션함수에서 사용하는 쿠키의 유효경로는 "/"로 되어 있습니다. 물론 php.ini의 옵션 session.cookie_path에 설정된 값이 기본값이 되는 것이지요.
유효도메인 지정하기
복수 도메인에 쿠키를 사용하기 위해서는 아래와 같이 도메인의 앞쪽 부분을 생략하여 지정하여야 합니다. ".phpclass.com"라고 지정하면 www.phpclass.com, hwooky.phpclass.com, ..... 와 같이 뒤쪽이 일치하는 모든 도메인에서 쿠키를 사용할 수 있습니다. 그러나 www.phpclass.net라는 도메인에서는 쿠키를 사용할 수 없습니다.
[code php;gutter:false] setcookie("mycookie", "cookie_value", $expire, $path, ".phpclass.com"); [/code]
이것은 호스트 이름이 phpclass.com 도메인에 있는 모든 서버들로 쿠키를 전송하도록 브라우저에 알립니다.
쿠키의 보안 지정하기
타인으로부터 보호해야 할 민감한 정보가 쿠키에 포함되어 있을 때에 지정할 수 있는 매개변수입니다. 서버가 SSL(Secure Sockets Layer)을 지원할 때만 쿠키를 전송합니다.
배열값 쿠키 설정하기
도메인당 쿠키는 최대 20개까지 저장할 수 있다는 것은 앞에서도 언급한 바 있습니다. 그런데 관련서적을 보면 배열을 이용하면 여러 개의 값들을 하나의 쿠키에 저장시킬 수 있다고 되어 있습니다. 즉, 쿠키를 하나의 배열로 다루고, 그 배열에 있는 각 구성 요소에 값을 지정하는 것입니다. 그리고 이러한 경우의 예를 아래와 같다고 하였습니다. 아래의 예제들은 거의 모두 PHP 3.0.14에서 실험한 결과입니다.
[code php;gutter:false] if (!isset($mycookie[0])) {
setcookie("mycookie[0]", "hwooky");
}

$mycookie[1]++;
setcookie("mycookie[1]", $mycookie[1]);

echo ("Hello $mycookie[0], you've seen this page " .
$mycookie[1] . ($mycookie[1] == 1 ? " time!" : " times!")); [/code]
그러나 위와 같은 방법으로 배열 각 요소를 쿠키에 저장하게 되면 역시 각 배열 요소가 하나의 쿠키로 저장되기 때문에 20개가 넘는 배열 요소를 저장할 수 없습니다. 아래는 이 때 생성되는 쿠키입니다.
mycookie[1]
7
www.safety.katri/exam2/cookie/
0
2023223680
29397420
3081596640
29397410
*
mycookie[0]
hwooky
www.safety.katri/exam2/cookie/
0
1993223680
29397420
3054096640
29397410
*
그러면 실제로 20개가 넘는 배열 요소를 가지고 위와 같은 방법으로 쿠키를 구워 보도록 하죠. 아래는 이러한 경우의 예입니다.
[code php;gutter:false] <?php

for ($i=0;$i<26;$i++)
setcookie("cookie[$i]", "$i");

if (!isset($cookie)) {
echo "<META http-equiv='Refresh' content='0; URL=$PHP_SELF'>";
exit;
}

?>

<P>document.cookie에서 확인한 쿠키정보</P>
<SCRIPT language=JavaScript>
<!--
cookie_str = document.cookie;
while (-1 != cookie_str.indexOf(';')) {
current = cookie_str.substring(0, cookie_str.indexOf(';')+1);
cookie_str = cookie_str.substring(cookie_str.indexOf(';')+1);
document.write(current + '\n');
}
document.write(cookie_str + '\n');
//-->
</SCRIPT> [/code]
위 소스코드를 실행하면 아래와 같이 20개의 배열요소만 쿠키에 저장되어 있는 것을 확인할 수 있습니다. 여기서 하나 더 주의깊게 살펴볼 것이 있습니다. 쿠키를 구워낸 순서와 반대로 저장된다는 것입니다. 이것은 PHP3에서의 결과이며 뒤에서도 언급하겠지만 PHP4에서는 이 순서가 뒤바뀌게 됩니다.
document.cookie에서 확인한 쿠키정보

cookie[19]=19;
cookie[18]=18;
cookie[17]=17;
cookie[16]=16;
cookie[15]=15;
cookie[14]=14;
cookie[13]=13;
cookie[12]=12;
cookie[11]=11;
cookie[10]=10;
cookie[9]=9;
cookie[8]=8;
cookie[7]=7;
cookie[6]=6;
cookie[5]=5;
cookie[4]=4;
cookie[3]=3;
cookie[2]=2;
cookie[1]=1;
cookie[0]=0
쿠키를 구워낼 때 배열 요소 대신에 배열명을 지정하면 어떻게 될까요? 지금부터 알아보도록 하겠습니다.
[code php;gutter:false] <?php

if (!isset($mycookie)) {
$mycook = array("mycook1"
, "mycook2"
, "mycook3"
, "mycook4"
, "mycook5"
, "mycook6"
, "mycook7"
, "mycook8"
, "mycook9"
, "mycook10"
, "mycook11"
, "mycook12"
, "mycook13"
, "mycook14"
, "mycook15"
, "mycook16"
, "mycook17"
, "mycook18"
, "mycook19"
, "mycook20"
, "mycook21"
, "mycook22"
, "mycook23"
, "mycook24"
, "mycook25"
);

setcookie("mycookie", $mycook, time()+3600);
die("<META http-equiv='Refresh' content='0; URL=$PHP_SELF'>");
} else {
setcookie("mycookie", "", time()-3600*24*365);
if (is_array($mycookie))
while (list($name,$value)=each($mycookie))
echo "$name=$value\n";
else
echo "(no array)$mycookie\n";
}

?> [/code]
실행 결과는 아래와 같습니다.
(no array)Array
서버에서 받은 쿠키를 확인하면 배열값이 넘어오는 것이 아니라 단순 문자열 "Array"가 넘어온다는 것을 알 수 있습니다. 그럼 실제로 로컬 시스템에 저장된 쿠키는 어떻게 되었을까요? 그것을 알아보기 위해 로컬시스템에 저장된 쿠키파일을 살펴보았습니다. 아래는 위의 소스를 익스 5.0에서 실행한 후에 "c:\windows\cookies\hwooky@cookie[1].txt"에 저장된 쿠키 파일 내용입니다.
mycookie
Array
www.safety.katri/exam2/cookie/
0
2298062848
34459487
537668192
29397773
*
첫번째 줄의 mycookie가 쿠키명이고, Array가 쿠키값입니다. 각 배열요소값은 저장되지 않고 setcookie("mycookie", $mycook, time()+3600)를 이용해 쿠키를 만들 때 값으로 지정된 배열변수 $mycook의 변수형만 쿠키파일에 저장되는 것을 볼 수 있습니다. 그러면 쿠키를 서버에서 클라이언트로 보낼 때 배열요소값은 생략하고 변수형 "Array"라는 문자열만 보낸 것이 아닐까요? 서버에서 클라이언트로 쿠키를 보낼 때 쿠키정보를 응답헤더에 첨부해서 보낸다는 것은 앞장에서 살펴보았습니다. 그래서 실제로 어떤 정보를 응답헤더에 첨부해서 클라이언트로 보내는지 확인하기 위해 응답헤더를 직접 확인하였습니다. 아래는 위의 소스를 실행할 때 발생하는 응답헤더를 모니터링한 것입니다.
http/1.1 200 ok:
date: Tue, 06 Feb 2001 12:57:21 GMT
server: Apache/1.3.14 (Unix) PHP/4.0.3pl1 PHP/3.0.14
x-powered-by: PHP/3.0.14
set-cookie: mycookie=Array; expires=Tuesday, 06-Feb-01 13:57:21 GMT
connection: close
content-type: text/html
위의 응답헤더를 보면 알겠지만 클라이언트로 보내는 쿠키정보에는 $mycook 변수형만 첨부되어 있지 배열요소는 클라이언트로 보내지 않는다는 것을 알 수 있습니다. 이를 다시 확인하기 위해 브라우저에서 서버로 보내지는 환경변수 "HTTP_COOKIE"를 확인하여 보겠습니다. 브라우저에 있는 쿠키 정보는 요구헤더를 통해 웹서버로 전달되며 웹서버가 요구헤더를 이용하여 환경변수 "HTTP_COOKIE"를 설정하도록 되어 있습니다. 요구헤더에 포함된 쿠키정보의 구조에 대하여는 앞장에서 살펴보았습니다.
[code php;gutter:false] <?php

if (!isset($mycookie)) {
$mycook = array("mycook1"
, "mycook2"
, "mycook3"
, "mycook4"
, "mycook5"
, "mycook6"
, "mycook7"
, "mycook8"
, "mycook9"
, "mycook10"
, "mycook11"
, "mycook12"
, "mycook13"
, "mycook14"
, "mycook15"
, "mycook16"
, "mycook17"
, "mycook18"
, "mycook19"
, "mycook20"
, "mycook21"
, "mycook22"
, "mycook23"
, "mycook24"
, "mycook25"
);

setcookie("mycookie", $mycook, time()+3600);
die("<META http-equiv='Refresh' content='0; URL=$PHP_SELF'>");
} else {
setcookie("mycookie", "", time()-3600*24*365);
if (is_array($mycookie))
while (list($name,$value)=each($mycookie))
echo "$name=$value\n";
else
echo "ENV=[".getenv("HTTP_COOKIE")."]\n";
}

?> [/code]
위 소스의 실행 결과는 다음과 같습니다. 실행 결과를 보면 알겠지만 환경변수 "HTTP_COOKIE"를 통해 전달되는 쿠키정보는 "mycookie=Array"이 전부입니다. 결국 배열 $mycook의 값을 쿠키로 굽더라도 브라우저에 저장된 쿠키값은 배열요소 전부가 아니라 변수형 "Array"만 쿠키파일에 저장된다는 것을 알 수 있습니다.
ENV=[mycookie=Array]
이러한 현상은 setcookie() 함수 대신에 아래와 같이 직접 header() 함수를 이용할 때도 동일하게 나타납니다.
[code php;gutter:false] $expires = gmdate("D, j-M-Y H:i:s", time() + 3600)." GMT";
header("Set-Cookie: mycookie=$mycook; expires=$expires"); [/code]
쿠키정보를 브라우저로 보내려면 setcookie() 함수를 이용하지만 PHP 스크립터 내부에서는 최종적으로 php3_header() 함수를 통해 응답헤더의 일부로 쿠키정보를 브라우저에 전달합니다. 아래는 PHP3.0.14 소스파일 head.c에 있는 아파치 웹서버에 대한 php3_header() 함수를 요약한 것입니다.
[code c;gutter:false] /*
소스 파일 위치 : ......\php-3.0.14\functions\head.c
*/

PHPAPI int php3_header(void)
{
......(중간생략)......

cookie = php3_PopCookieList();
while (cookie) {
if (cookie->name)
len += strlen(cookie->name);
if (cookie->value) {
cookievalue = _php3_urlencode(cookie->value, strlen (cookie->value));
len += strlen(cookievalue);
}

......(중간생략)......

tempstr = emalloc(len + 100);
if (!cookie->value || (cookie->value && !*cookie->value)) {

......(중간생략)......

} else {
/* FIXME: XXX: this is not binary data safe */
sprintf(tempstr, "%s=%s", cookie->name, cookie->value ? cookievalue : "");
if (cookie->name) efree(cookie->name);
if (cookie->value) efree(cookie->value);
if (cookievalue) efree(cookievalue);
cookie->name=null;
cookie->value=null;
cookievalue=null;
if (cookie->expires > 0) {
strcat(tempstr, "; expires=");
dt = php3_std_date(cookie->expires);
strcat(tempstr, dt);
efree(dt);
}
}
if (cookie->path && strlen(cookie->path)) {
strcat(tempstr, "; path=");
strcat(tempstr, cookie->path);
efree(cookie->path);
cookie->path=null;
}
if (cookie->domain && strlen(cookie->domain)) {
strcat(tempstr, "; domain=");
strcat(tempstr, cookie->domain);
efree(cookie->domain);
cookie->domain=null;
}
if (cookie->secure) {
strcat(tempstr, "; secure");
}
table_add(GLOBAL(php3_rqst)->headers_out, "Set-Cookie", tempstr);
if (cookie->domain) efree(cookie->domain);
if (cookie->path) efree(cookie->path);
if (cookie->name) efree(cookie->name);
if (cookie->value) efree(cookie->value);
if (cookievalue) efree(cookievalue);
efree(cookie);
cookie = php3_PopCookieList();
efree(tempstr);
}
GLOBAL(php3_HeaderPrinted) = 1;
GLOBAL(header_called) = 1;
send_http_header(GLOBAL(php3_rqst));

......(중간생략)......

}

......(중간생략)......

GLOBAL(header_is_being_sent) = 0;
return(1);
} [/code]
위 함수에는 응답헤더에 포함되는 쿠키 정보 문자열 "set-cookie: mycookie=Array; expires=Tuesday, 06-Feb-01 13:57:21 GMT"을 만드는 과정이 나와 있고 최종적으로는 모든 작성된 쿠키 정보 문자열들을 브라우저로 전송(함수 send_http_header)하는 것으로 함수가 종료됩니다. 함수를 분석해 보면 _php3_urlencode(cookie->value, strlen (cookie->value))에 의해 배열에 대한 쿠키값이 "Array"로 변환되는 것을 볼 수 있고 배열요소가 쿠키 정보 문자열에 포함되지 않는다는 것을 알 수 있습니다. 여기에서 배열요소는 모두 사라지게 되는 것입니다.
하나의 쿠키에 배열을 담기 위한 노력
배열요소가 20개 이상 존재한다면 그대로 쿠키로 저장할 수는 없습니다. 이때는 배열을 직렬화(serialize)하여 하나의 문자열로 만든 다음 이 문자열을 쿠키로 만드는 것입니다. 쿠키를 읽어 들일 때는 반대로 문자열을 원래의 배열로 만들기 위해 unserialize 하는 것입니다. 이러한 방법은 세션함수에서 이용하는 방법으로 가장 신뢰성있는 방법입니다.
[code php;gutter:false] <?php

if (!isset($mycookie)) {
$mycook = array("mycook1"
, "mycook2"
, "mycook3"
, "mycook4"
, "mycook5"
, "mycook6"
, "mycook7"
, "mycook8"
, "mycook9"
, "mycook10"
, "mycook11"
, "mycook12"
, "mycook13"
, "mycook14"
, "mycook15"
, "mycook16"
, "mycook17"
, "mycook18"
, "mycook19"
, "mycook20"
, "mycook21"
, "mycook22"
, "mycook23"
, "mycook24"
, "mycook25"
);

$value = serialize($mycook);
setcookie(
"mycookie",
get_magic_quotes_gpc() ? $value : addslashes($value),
time+3600
);
die("<META http-equiv='Refresh' content='0; URL=$PHP_SELF'>");
} else {
setcookie("mycookie", "", time()-3600*24*365);
$mycook = unserialize(stripslashes($mycookie));
if (is_array($mycook))
while (list($name,$value)=each($mycook))
echo "$name=$value\n";
else
echo "ENV=[".getenv("HTTP_COOKIE")."]\n";
}

?> [/code]
위에서 get_magic_quotes_gpc()를 이용하는 부분이 있을 것입니다. php.ini 설정 파일에 있는 옵션 magic_quotes_gpc의 설정상태에 따라 적절히 처리해 주지 않으면 저장된 쿠키를 제대로 읽을 수가 없습니다. 제가 공개한 세셔너 또는 쿠키 관련 자료들이 제대로 동작하지 않는다면 이 부분을 의심해 보아야 합니다. 제가 실험한 웹서버의 환경에서는 magic_quotes_gpc의 값이 ON으로 설정되어 있기 때문에 저장된 값에는 '(single-quote), "(double-quote), \(backslash), 널(NUL) 들의 앞에 백슬래시가 자동으로 붙게 됩니다. 따라서 이러한 경우에는 쿠키를 읽을 때 반드시 stripslashes() 함수를 이용하여 자동으로 붙은 백슬래시를 제거해야 합니다. 그런데 여러분의 웹서버 환경에서 magic_quotes_gpc의 값이 OFF로 되어 있다면 제가 공개한 자료들이 실행에 문제가 생길 수 있습니다. 단순한 숫자나 영문자로 구성된 쿠키값일 때는 관계없으나 serialize() 함수로 직렬화된 문자열의 경우는 꼭 문제가 생기지요. get_magic_quotes_gpc() 부분을 삽입한 것은 웹서버의 설정상태에 관계없이 동작시키기 위해 작성된 것이니 참조바랍니다.
위 소스의 실행 결과는 다음과 같습니다. 이제야 제대로 배열이 저장되는 것 같네요.
0=mycook1
1=mycook2
2=mycook3
3=mycook4
4=mycook5
5=mycook6
6=mycook7
7=mycook8
8=mycook9
9=mycook10
10=mycook11
11=mycook12
12=mycook13
13=mycook14
14=mycook15
15=mycook16
16=mycook17
17=mycook18
18=mycook19
19=mycook20
20=mycook21
21=mycook22
22=mycook23
23=mycook24
24=mycook25
쿠키 사용을 위한 PHP 설치 옵션
쿠키로부터 전달받은 값이 서버 설치 옵션에 따라 전역변수로 받을 수도 있고 전역배열변수 $HTTP_COOKIE_VARS[]로 받을 수도 있습니다.
그런데 $HTTP_COOKIE_VARS[]을 언제나 사용할 수 있는 것은 아니고, PHP를 서버에 설치할 때 지정한 옵션에 따라 달라지지요. $HTTP_COOKIE_VARS[]와 관련된 서버 세팅은 두가지입니다. 하나는 소스 컴파일할 때 "--enable-track-vars"라는 설정옵션을 지정하여야 합니다. 두번째는 "--enable-track-vars"를 지정하여 소스 컴파일을 하더라도 php.ini 파일에 있는 track_vars 지시자에 의해 $HTTP_COOKIE_VARS[]를 Enable 할 수도 있고 Disable 할 수도 있습니다. 아래와 같이 track_vars 지시자를 Enable 하십시요.
php.ini의 내용중
================

track_vars = On ; enable the $HTTP_*_VARS[] arrays, where * is one of
; ENV, POST, GET, COOKIE or SERVER.
만약 여러분의 서버가 "--enable-track-vars"를 지정하여 소스 컴파일되어 있지 않다면 PHP_COOKIE_VARS를 사용하시기 전에 문서 최상단에 아래와 같이 php_track_vars 지시자를 사용하세요.
[code php;gutter:false] <?php_track_vars?>
<?php
.
.
.
?> [/code]
주의할 점은 php_track_vars 지시자가 PHP3에서만 제대로 동작되며, PHP4부터는 php_track_vars 지시자를 사용하지 않습니다. PHP4에서 track_vars 의 설정값이 "1"일 때에 php_track_vars 지시자를 사용하게 되면 아래와 같은 에러가 발생합니다.
Warning: <?php_track_vars?> is no longer supported
- please use the track_vars INI directive instead in ...... on line ???
PHP 4.0.3부터는 track_vars가 자동적으로 (항상) ON 상태입니다. 따라서 PHP 4.0.3부터는 php.ini의 track_vars의 설정 상태에 관계없이 php_track_vars 지시자를 사용하면 무조건 위와 같은 에러가 발생합니다.
PHP의 변수이름은 알파뉴머릭과 밑줄로만 이루어져 있습니다. 만약 쿠키명에 유효하지 않은 문자들이 포함되어 있다면 유효하지 낳은 문자들은 밑줄(_)로 변환됩니다. 예를 들어, 쿠키명 "in%va.lid_"는 "in_va_lid_"로 변환됩니다.
$HTTP_COOKIE_VARS[]를 사용하여야 할 이유는?
$HTTP_COOKIE_VARS["username"] 대신에 전역변수 $username를 사용하여도 동작결과는 동일합니다. 그러면 언제 $HTTP_COOKIE_VARS[]을 사용하여야 할까요? 이전페이지에서 세션값, GET, POST, 쿠키로 넘어 오는 모든 값은 전역변수로 넘어올 수도 있고 $HTTP_SESSION_VARS[], $HTTP_GET_VARS[], $HTTP_POST_VARS[], $HTTP_COOKIE_VARS[]와 같은 전역 배열 변수로도 넘어오지요. 여기서 보았듯이 배열로 넘어오는 값들은 각 요소(세션, GET, POST, 쿠키)마다 서로 다른 배열변수에 담겨오기 때문에 배열변수가 무엇이냐에 따라 넘어온 값이 어떠한 성격을 가지고 있는지 파악할 수 있습니다. 그러나 전역변수로 넘어온 값은 전역변수명만을 가지고는 그 값이 세션값이었는지, HTTP GET 방식으로 넘어왔는지, HTTP POST 방식으로 넘어왔는지, 쿠키값이었는지가 구분이 되지 않습니다. 사용상의 편이성만으로만 보면 전역변수를 사용하는 것이 좋겠지요. 그러나 보안이라는 측면에서 보면 넘어온 값의 성격을 구분하지 못할 때는 문제가 발생할 수 있습니다. 예를 들어 앞장(home.php)에서 아래와 같이 HTTP POST 방식으로 userid와 passwd값을 입력받아 서브밋하였습니다.
[code php;gutter:false] <FORM name=getID method="post" action="login_process.php">
<P>사용자ID : <INPUT type="text" name="login_userid" size="15"></P>
<P>비밀번호 : <INPUT type="password" name="login_passwd" size="15"></P>
</FORM> [/code]
이 값을 다음 장(login_process.php)에서 받았을 때 $HTTP_POST_VARS[] 배열을 사용하지 않고 전역변수 $login_userid, $login_passwd를 직접 사용한다면 이 값이 꼭 앞장 양식에서 입력되어 들어온다는 보장이 없습니다. 누군가가 부당한 목적을 위해 앞장을 통하지 않고 아래와 같이 URL 파라미터로 값을 입력할 수도 있지요.
login_process.php?login_userid=user3&login_passwd=test
위와 같이 URL 파라미터로 login_process.php 페이지로 $login_userid, $login_passwd 값을 전달할 수 있지요.
아래와 같은 세션값도 마찬가지입니다. $access_userid 값과 $access_userid 값은 login_process.php 페이지에서 home.php 페이지로 세션을 통해 비밀스럽게(?) 전달되어 인증처리를 하여야 하는데 역시 누군가가 부당한 목적을 위해 세션을 통하지 않고 URL 파라미터를 통해 $access_userid 값과 $access_userid 값을 home.php 페이지로 전달할 수 있지요.
이것을 방지하기 위해 각 요소(세션, GET, POST, 쿠키)마다 배당된 다른 배열변수를 이용해 전역변수를 덮어쓰기하는 것입니다.
보안상 신경쓰지 않아도 되는 전역변수 값이야 이렇게 할 필요가 없으나 인증에 필요한 값들은 불편하더라도 이같은 코딩 습관에 익숙하시는 것이 바람직합니다.
공개 소스 중에는 이렇게까지 하지 않는 경우도 많이 있으나 여러분이 이러한 면에도 관심을 가져주었으면 해서 때에 따라서는 불필요할 지도 모르지만 코드를 일부로 포함시켰습니다.
쿠키 삭제하기
쿠키는 보통 setcookie() 함수의 첫번째 매개변수만으로 삭제할 수 있습니다.
[code php;gutter:false] setcookie("mycookie"); [/code]
그러나 때에 따라서는 첫번째 매개변수만 지정할 경우 해당 쿠키가 삭제되지 않는 경우를 볼 수 있습니다. 이것은 쿠키를 설정할 때 유효도메인, 유효경로를 지정한 경우가 대부분입니다. 이와 같은 경우에는 쿠키 설정할 때 지정된 유효도메인과 유효경로를 삭제시에도 지정하여야 합니다.
[code php;gutter:false] setcookie("mycookie", "cookie_value", 0, "/exam", ".phpclass.com"); [/code]
예를 들어 쿠키 설정할 때 위와 같이 지정하였다면, 쿠키 삭제할때는 아래와 같이 지정하여야 합니다. 삭제할 때 유효기간 설정값은 예를 들은 것 뿐이며 적절한 과거 시점을 지정하면 됩니다.
[code php;gutter:false] setcookie("mycookie", "", time()-31536001, "/exam", ".phpclass.com"); [/code]
현재 설정된 쿠키 변수들에는 영향을 미치지 않으며, 또한 $HTTP_COOKIE_VARS[]도 변경시키지 않는다.

 

쿠키의 생성, 참조, 삭제되는 시점
setcookie() 함수로 쿠키를 생성하거나 삭제하더라도 새로운 HTTP 요구(require)가 없으면 이 쿠키에 대한 정보가 쿠키용 전역변수 또는 전역배열변수 $HTTP_COOKIE_VARS[]에 적용되지 않습니다. 이러한 setcookie() 함수의 동작원리를 잘 이해하고 있어야 합니다. 따라서 위에서와 같이 setcookie("mycookie")를 통해 쿠키를 삭제하더라도 현재 설정된 쿠키 전역변수와 전역배열변수 $HTTP_COOKIE_VARS[]의 내용은 계속 유지됩니다. setcookie() 함수를 통해 쿠키를 생성하면 이 값은 로컬시스템(사용자 하드드라이브)에 저장되었다가 다음 페이지를 읽을 때 쿠키정보를 서버로 보내게 됩니다. 서버는 이 쿠키정보를 이용하여 전역변수값으로 설정해 주지요.
setcookie() 함수 사용시 발생하는 에러
setcookie() 함수를 사용하는 데 주의 할 점이 있습니다. setcookie() 함수는 일반적인 HTML 태그 또는 PHP로부터 보내지는 실제의 출력 이전에 호출되어야 합니다. setcookie() 함수를 호출하기 전에 include() 또는 auto_prepend를 통하여 코드를 읽어들일 수 있는데 이러한 코드에 브라우저로 출력되는 스페이스 또는 빈줄이 있으면 에러가 발생합니다. 이 에러에 대한 것은 제 홈페이지의 Q&A 게시판에서 언급되어 있으며, 메뉴 "후키라이브러리 >> 캐시리미터 >> 헤더 관련 PHP 함수" 의 header() 함수에서도 언급되어 있으니 참조바랍니다. 아래는 이 때 PHP3 및 PHP4에서 발생하는 에러메시지입니다.
PHP3일 때
=========
Warning: Oops, php3_SetCookie called after header has been sent
in /home/....../test.php3 on line ???

PHP4일 때
=========
Warning: Cannot add header information - headers already sent by
(output started at /home/....../test.php:3)
in /home/....../test.php on line ???
setcookie() 함수 호출 순서
PHP3에서의 실험
PHP는 쿠키들을 PHP 스크립트에 있는 setcookie() 호출들의 순서와 역순으로 서버로 전달합니다. 앞에서 배열요소를 쿠키에 저장할 때도 확인하였습니다. 어떻게 해서 이런 현상이 발생하였을까요? 이를 확인하기 위해 다시 소스코드를 분석해 보겠습니다. 아래는 PHP3.0.14 소스파일 head.c에 있는 아파치 웹서버에 대한 php3_header() 함수 및 _php3_SetCookie() 함수를 요약한 것입니다. head.c 파일은 PHP3.0.14 소스파일의 압축을 풀면 php-3.0.14\functions\head.c에 있습니다.
[code c;gutter:false] void _php3_SetCookie(char * name, char * value, time_t expires
, char * path, char * domain, int secure)
{
......(중간생략)......

if (name) name = estrdup(name);
if (value) value = estrdup(value);
if (path) path = estrdup(path);
if (domain) domain = estrdup(domain);
php3_PushCookieList(name, value, expires, path, domain, secure);
} [/code]
SetCookie() 함수는 내부적으로 결국 _php3_SetCookie() 함수를 실행하게 되어있는데 이 함수가 하는 일이라고는 단지 쿠키 설정 정보들을 CookieList라는 스택 자료 구조에 저장(Push)하는 것 뿐입니다.
[code c;gutter:false] PHPAPI int php3_header(void)
{

......(중간생략)......

cookie = php3_PopCookieList(); //<-- 스택으로부터 데이터를 가져음
while (cookie) {

......(중간생략)......

cookie = php3_PopCookieList(); //<-- 스택으로부터 데이터를 가져옴
efree(tempstr);
}
......(중간생략)......

send_http_header(GLOBAL(php3_rqst)); //<-- 응답헤더 전송

......(중간생략)......

return(1);
} [/code]
응답헤더를 통해 보낼 정보(쿠키정보 포함)가 다 모아지면 php3_header() 함수를 실행하게 됩니다. 이 함수를 살펴보면 위에서와 같이 SetCookie() 함수를 통해 스택 CookieList에 모아진 자료를 하나씩 차례로 불러와 헤더 정보에 추가하는 것을 알 수 있습니다.
자료구조론을 읽어보신 분은 이미 이해하셨겠지만 CookieList가 스택구조다 보니 저장(Push)될 때와 반대의 순서로 읽어(Pop) 들인다는 것(후입선출구조)입니다. 그러니 응답헤더에 포함되는 순서가 SetCookie() 함수 실행순서와 뒤바뀌게 되고 결국 쿠키가 구워지는 순서가 뒤바뀌게 되는 것이지요.
제가 공개하는 쿠커(Cooker)와 같이 때에 따라서는 이 순서가 바뀌면 안돼는 웹애플리케이션도 필요할 것입니다. 이러한 경우는 어떻게 해야 할까요. 해결방법은 두가지, 자바스크립트를 이용하던가 아니면 header() 함수를 이용하시면 됩니다. 쿠커에서는 이 문제때문에 setcookie() 함수 대신에 header() 함수를 이용하였습니다.
setcookier() 호출 순서와 역순으로 브라우저에서 쿠키가 생성되거나 삭제되기 때문에 만약 동일한 이름을 가진 쿠키를 삭제하고 새롭게 다른 값으로 설정하기를 원한다면 setcookie()로 새로운 쿠키를 먼저 설정한 다음, 나중에 다시 setcookie()를 호출하여 예전의 쿠키를 삭제해야 합니다.
[code php;gutter:false] <?php
// 새로운 쿠키를 설정
setcookie("mycookie", "cookie_value");
// 예전의 쿠키를 삭제
setcookie("mycookie");
?> [/code]
PHP4에서의 실험
실험까지는 하지 않았고 PHP4 메뉴얼에 의하면 setcookie() 함수 호출 순서와 서버로 전달되는 순서가 같게 변경되었습니다. 제 개인 생각으로도 PHP4에서의 방법이 옳지 않나 생각합니다. 뒤에서 언급된 쿠키정보클래스 "쿠커(Cooker)에서도 이 호출순서와 서버로 전달되는 순서가 역순이라 setcookie() 함수를 사용할 수가 없었습니다. 그래서 setcookie() 함수 대신에 header() 함수를 직접 이용하게 되었지요. 쿠커를 작성할 때 PHP4에서는 setcookie() 함수를 사용해도 되겠지만 PHP3와의 호환성을 위해 setcookie() 함수를 사용하지 않았습니다.

'phpsource > 캐시&세션&쿠키' 카테고리의 다른 글

{쿠커}9.쿠커  (0) 2001.02.20
{쿠커}8.document.cookie 객체  (0) 2001.02.20
{쿠커}6.쿠키 다루기  (0) 2001.02.20
{쿠커}5.쿠키 규격  (0) 2001.02.20
{쿠커}4.브라우저 설정  (0) 2001.02.20
Posted by 방글24
쿠키 생성 및 접근
쿠키를 생성하기 위해서는 웹 서버가 앞장에서 다룬 쿠키 규격에 맞게 "Set-Cookie" HTTP 헤더 정보를 보내면 됩니다. 즉 HTTP 헤더를 생성하는 CGI를 작성하면 원하는 내용을 쿠키에 입력하는 것이 가능합니다. 클라이언트에 저장된 쿠키를 꺼내기 위해서는 클라이언트가 정보요청을 할 때(즉 CGI을 불렀을 때) 함께 넘어오는 환경변수 HTTP-COOKIE에 저장되어 있는 정보를 추출하여 사용하면 됩니다. PHP 또는 자바스크립트에서는 이러한 작업을 아주 쉽게 할 수 있는 방법을 제시합니다. 물론 C언어와 같은 다른 수단을 사용하더라도 쿠키 규격을 만족하도록 HTTP 헤더 또는 환경변수를 다루면 되지만 PHP 또는 자바스크립트보다는 좀 다루기가 쉽지 않을 것입니다.
여기서는 PHP와 자바스크립트를 이용하여 쿠키를 다루는 방법에 대하여 기술할 것입니다. 자세한 것은 다음 장 "setcookie() 함수" 및 "document.cookie 객체"를 참조바랍니다.
PHP
쿠키를 생성하기 위한 함수로 SetCookie() 함수를 제공하며, 클라이언트에서 전달된 쿠키는 쿠키명에 해당하는 전역변수를 가지고 다루거나 아니면 $HTTP_COOKIE_VARS[]라는 전역배열변수를 가지고 다룰 수 있습니다.
[code php;gutter:false] <?php

if (!isset($mycookie)) {
setcookie("mycookie", "cookie_value", time+3600);
die("<META http-equiv='Refresh' content='0; URL=$PHP_SELF'>");
} else {
echo "$mycookie<BR>\n";
}

?> [/code]
자바스크립트
document.cookie 객체는 쿠키의 모든 이름과 값을 가지고 있고, 자바스크립트에서 이 속성(property)을 이용할 수 있습니다. 사용자들은 아래와 같이 document.cookie를 마치 문자열 변수처럼 취급하여 쉽게 쿠키의 정보를 제어할 수 있습니다.
[code javascript;gutter:false] document.cookie = "ID=" + escape("123456789")
+ "; expires=Thu, 01-Jan-70 00:00:01 GMT"
+ "; path=/exam"
+ "; doamin=.phpclass.com"
+ "; secure"; [/code]

'phpsource > 캐시&세션&쿠키' 카테고리의 다른 글

{쿠커}8.document.cookie 객체  (0) 2001.02.20
{쿠커}7.setcookie() 함수  (0) 2001.02.20
{쿠커}5.쿠키 규격  (0) 2001.02.20
{쿠커}4.브라우저 설정  (0) 2001.02.20
{쿠커}3.보안  (0) 2001.02.20
Posted by 방글24
쿠키 규격에 관련된 자료
아래에는 쿠키 규격(HTTP Cookies Specification)에 관련된 문서를 링크시켜 놓았습니다.
  • 넷스케이프의 쿠키에 관한 예비 규격서(www.netscape.com/newsref/std/cookie_spec.html)
    (수정:2010.1.11) 오래된 문서라서 현재는 링크가 깨진 상태입니다. 복사본을 참조하세요.
  • RFC2109 : Proposed Standard "HTTP State Management Mechanism"(www.cis.ohio-state.edu/htbin/rfc/rfc2109.html)
    IETF(Internet Engineering Task Force)의 HTTP Working Group에서 쿠키의 표준화 작업을 하고 있으며 현재의 쿠키는 RFC 2109를 따르고 있습니다.
    (수정:2010.1.11) 오래된 문서라서 현재는 링크가 깨진 상태입니다. 복사본을 참조하세요.
쿠키의 설정
위 규격에 의해 HTTP 서버에서는 다음과 같은 구조의 Set-Cookie 헤더를 통해 쿠키를 클라이언트로 전달합니다.
Set-Cookie: NAME=VALUE; expires=DATE; path=PATH; domain=DOMAIN_NAME; secure
대문자는 사용자가 특정값을 입력하는 부분이고 소문자는 예약어로서 반드시 그대로 써야만 합니다.
쿠키 헤더 문법에는 쿠키내용, 유효기간, 유효경로, 유효도메인, 보안설정의 다섯가지의 구성요소를 가집니다. 여기에서 여기서 쿠키명과 쿠키값으로 이루어지는 실질적인 쿠키내용을 제외한 다른 구성요소는 모두 쿠키의 유효 여부를 판단하는데 사용됩니다. 즉 각 구성요소에 입력된 값과 모두 일치하는 서버만이 그 쿠키를 참조할 수 있는 것입니다.
구성요소 문법 필수/선택 예제
쿠키내용 NAME=VALUE 필수 ID=123456789
유효기간 expires=DATE 선택 expires=Tuesday, 06-Feb-01 13:57:21 GMT
유효경로 path=PATH 선택 path=/exam
유효도메인 domain=DOMAIN_NAME 선택 domain=.phpclass.com
보안설정 secure 선택 secure
쿠키내용 NAME=VALUE
실제 쿠키의 내용을 입력하는 곳으로 저장될 쿠키명과 쿠키값을 설정합니다. 쿠키내용은 Set-Cookie 헤더에서 반드시 설정하여야 하는 필수적인 필드입니다. 쿠키명이나 쿠키값의 문자열 중에는 세미콜론(;),콜론(,) 또는 공백값이 들어갈 수 없습니다. 이러한 특수문자들을 표현하기 위해서는 URL 인코딩 방식에 따라 %3B와 같은 형태로 기술해주면 된다.
URL 인코딩/디코딩함수 자바스크립트 PHP
인코딩 escape() urlencode()
디코딩 unescape() urldecode()
유효기간 expires=DATE
쿠키의 유효기간을 설정하는 항목으로 유효기간이 지난 쿠키는 자동으로 지워집니다. 생략이 가능하며 특별히 명시하지 않았을 경우 브라우저 세션이 종료되는 순간 쿠키값이 자동으로 사라집니다. 날짜의 형식은 "Wdy, DD-Mon-YYYY HH:MM:SS GMT"과 같으며 여기서 Wdy란 요일, DD-Mon-YYYY는 일-월-년, HH:MM:SS는 시:분:초, GMT는 그리니치 표준시를 나타냅니다.
Sun, 01-Jan-1995 01:00:00 GMT
유효경로 path=PATH
경로 정보는 쿠키의 유효한 경로를 설정하는 항목입니다. 유효경로는 현재 디렉토리의 하위디렉토리를 모두 포함합니다. /exam 라고 설정하면 /exam 뿐만 아니라 /exam/cookie에서도 유효합니다. 또한 경로명의 부분 문자열로 지정할 수 있습니다. 즉 /exam의 경로로 설정된 쿠키는 /exam뿐만 아니라 /example에서도 유효하다. 만약 부분문자열이 아닌 문자열 전부가 일치한 디렉토리만 유효하도록 하려면 /exam/ 와 같이 뒤에 "/"를 지정합니다. 유효경로를 생략하면 쿠키를 지정하는 HTTP 응답 헤더와 같이 넘어오는 문서의 경로로 지정됩니다. 유효경로를 /라고 지정하면 쿠키를 서버의 모든 페이지에서 사용할 수 있습니다.
유효도메인 domain=DOMAIN_NAME
도메인 정보는 쿠키가 유효한 서버를 지정할 때 사용됩니다. 즉 여기서 지정된 도메인 이외의 서버에서는 이 쿠키의 값을 참조할 수 없습니다. 유효도메인을 지정하지 않으면 쿠키에 값을 입력한 서버의 호스트 이름이 지정됩니다.
복수 도메인에서 쿠키를 사용하기 위해서는 호스트명 앞쪽을 생략할 수 있습니다. 예를 들어 쿠키를 www.phpclass.com과 hwooky.phpclass.com 모두에서 사용하려면 .phpclass.com으로 유효도메인을 설정합니다.
보안정보 secure
쿠키의 마지막에 secure 설정이 지정되면 실제로 쿠키의 정보가 암호화되어 저장됩니다. 그러나 호스트가 SSL(Secure Sockets Layer)을 지원할 때(예를 들어 HTTPS 서버)만 유효하며(쿠키를 전송하며) 그 이외는 무시됩니다. 이것은 서버와 브라우저가 모두 보안을 지원한다는 것을 의미합니다. 만일 secure 인수가 없다면 쿠키가 네트워크 상에서 암호화되지 않은 채로 전송될 수 있다는 것을 의미합니다.
쿠키의 요청
쿠키가 설정된 이후에는 클라이언트가 서버에 문서를 요청할 때, 쿠키가 유효한지 검사하기 위해서 쿠키 리스트를 검사하는데 이 때 우선 유효도메인 검사하게 됩니다. 이 때 유효도메인과 서버의 도메인이 일치하는가를 뒤에서 부터 검사하는 방법(tail matching)을 이용합니다. 즉 유효도메인이 .phpclass.com라고 지정되어 있으면 이 쿠키는 www.phpclass.com, hwooky.phpclass.com abc.mingky.phpclass.com 등의 도메인과 일치하는 것으로 처리되지만 www.phpschool.com과 같은 경우는 불일치로 처리됩니다.
일단 도메인 정보의 확인 작업이 통과된 후 쿠키가 유효한 경로를 한번 더 확인하게 됩니다. 이러한 쿠키의 유효성을 통과한 쿠키는 다음과 같은 HTTP 요구헤더를 통해 웹서버로 쿠키에 대한 정보를 넘겨주게 됩니다.
Cookie: ID=12345678; PW=abcdefghi
쿠키의 동작
쿠키의 설정과 요청이 실제로 어떠한 절차로 이루어지는지 살펴보면 아래와 같습니다.
① 클라이언트가 서버측의 문서를 요청하면 다음과 같은 응답 헤더를 통해 쿠키가 설정됩니다.
Set-Cookie: ID=123456789; path=/exam; expires=Tuesday, 06-Feb-01 13:57:21 GMT
② 브라우저가 '/exam' 경로에 있는 웹문서를 요청할 때 서버로 요구 헤더를 통해 다음과 같은 쿠키 정보가 전달됩니다.
Cookie: ID=123456789
③ CGI 프로그램에서는 HTTP_COOKIE CGI 환경변수를 통해 쿠키명(ID)과 쿠키값(123456789)을 읽어 처리합니다.
쿠키의 제한사항
각 클라이언트는 여러 개의 쿠키를 가질 수 있습니다. 따라서 여러 서버에 접속하여도 각 서버에 해당하는 쿠키를 각각 따로 관리할 수 있습니다. 그러나 쿠키들의 남용을 방지하기 위해 웹브라우저가 관리하는 쿠키의 크기는 제한됩니다.
▶ 최대 300개의 쿠키 저장
▶ 하나의 쿠키는 공백을 포함하여 name/value의 합이 4KB로 제한
▶ 서버/도메인별로 최대 20개의 쿠키 저장
쿠키의 최대 저장 개수를 초과하면 이전에 저장된 쿠키는 새로운 쿠키가 덮어 쓰게 되며 , 이때 LRU(Least Recently Used), 방식에 따라 최근에 가장 적게 사용된 쿠키가 차례로 지워지게 됩니다.
쿠키를 유효기간 전에 파기시키려면 expires 속성을 지나간 시간으로 하여 재지정 해주면 됩니다. 이때는 쿠키명과 유효경로 등이 지우려는 쿠키의 정보와 일치해야 합니다.
Set-cookie 하나당 하나의 쿠키만 보낼 수 있습니다.

'phpsource > 캐시&세션&쿠키' 카테고리의 다른 글

{쿠커}7.setcookie() 함수  (0) 2001.02.20
{쿠커}6.쿠키 다루기  (0) 2001.02.20
{쿠커}4.브라우저 설정  (0) 2001.02.20
{쿠커}3.보안  (0) 2001.02.20
{쿠커}2.웹페이지 상태유지  (0) 2001.02.20
Posted by 방글24
쿠키 허용 여부 설정
넷스케이프 3.x와 인터넷 익스플로러 3.x에서는 쿠키 사용이 기본적으로 가능하기 때문에 따로 설정해 줄 필요가 없으나, 넷스케이프 4.x, 또는 인터넷 익스플로러 4.x 이상의 버전에서는 별도의 쿠키 설정이 필요합니다.
쿠키 사용을 원하지 않을 경우에는 웹브라우저의 설정항목에서 "사용 안함"을 선택하시면 됩니다. 그러면 쿠키는 전혀 전송되지 않을 것이며, 새로운 쿠키도 받아들여지지 않을 것입니다. "모든 쿠키받음" 또는 "사용"을 선택하면 서버로부터 오는 쿠키가 받아들여지고 저장된 쿠키가 전송될 것입니다. 때에 따라서는 쿠키가 제공될 때마다 경고 표시하도록 설정할 수 있습니다. 이 기능을 사용하면 쿠키를 사용하는 웹사이트를 접속할 때마다 쿠키 허용 여부를 묻는 경고 메시지가 나타나기 때문에 웹서핑하기AC가 불편할 것입니다. 많은 홈페이지가 쿠키를 사용하고 있기 때문에 웹서핑을 쾌적하게 즐기시려면 쿠키의 사용을 가능하게 해 주어야 합니다.
넷스케이프 네비게이터 4.0
작업 표시줄에서
1. 편집을 클릭한 다음
2. 환경설정을 선택합니다.
3. 고급을 클릭합니다.
4. "쿠키"란에서 옵션을 설정합니다.
< 넷스 4.0에서의 쿠키 설정 화면 >
인터넷 익스플로러 4.0
1. 보기 메뉴에서
2. 인터넷 옵션을 선택합니다.
3. 고급 탭을 클릭합니다.
4. 시스템 보안 아래의 노란색 느낌표 아이콘까지 아래로 스크롤하여
쿠키 사용 여부를 조정하는 세 가지 옵션 중 하나를 선택합니다.
인터넷 익스플로러 5.0
1. 도구 메뉴에서
2. 인터넷 옵션을 선택합니다.
3. 보안 탭을 클릭합니다.
4. 인터넷을 클릭한 다음 사용자 정의 단추를 누릅니다.
5. 쿠키까지 아래로 스크롤하여 옵션을 설정합니다.
< 익스 5.0에서의 쿠키 설정 화면 >
쿠키 파일
쿠키는 4K바이트 이하의 파일로서, 쿠키명과 값, 방문한 웹사이트의 이름 등의 정보가 담겨 있습니다. 쿠키가 저장되는 위치는 사용하고 있는 브라우저와 운영체제에 따라 다릅니다.
넷스케이프 네비게이터 4.0
넷스케이프는 모든 쿠키를 하나의 파일로 묶어 저장하며 윈도우 환경에서는 이와 같이 쿠키를 가지고 있는 파일을 "C:\Programs Files\Netscape\Users\<사용자명>\cookies.txt"에서 찾을 수 있습니다. 이와 같이 넷스케이프는 사용자별로 쿠키를 저장합니다. 로컬시스템의 사용자 설정에서 복수사용자 설정을 하지 않았다면 "C:\Programs Files\Netscape\Users\Default\cookies.txt"에서 쿠키 파일을 찾을 수 있습니다. 예를 들어 아래와 같은 쿠키 정보가 있다고 하죠.
# Netscape HTTP Cookie File
# http://www.netscape.com/newsref/std/cookie_spec.html
# This is a generated file! Do not edit.

.phpclass.com TRUE /exam2 FALSE 981449338 ID 5
쿠키 파일에 담겨지는 정보는 쿠키를 제공한 웹사이트의 이름, 쿠키의 유효기간, 쿠키명, 그리고 쿠키값 등이 있습니다. 위의 첫 칸은 쿠키를 제공한 URL 주소를 담고 있습니다. 위와 같은 경우 각 칸의 의미를 살펴보면 다음과 같습니다. 유효기간은 1970년을 기점으로 잡아 소멸되는 시점까지를 초단위로 나타냅니다.
.phpclass.com <- 도메인 설정
TRUE <- 도메인을 지정함(???)
/exam2 <- 경로 설정
FALSE <- 보안 설정
981449338 <- 유효기간 설정
ID <- 쿠키명
5 <- 쿠키값
인터넷 익스플로러 5.0
윈도우 환경에서 익스플로러를 실행하는 경우에는 쿠키들이 C:\Windows\Cookies 폴더에 여러 파일로 나뉘어서 저장됩니다. 그러나 이 파일들은 C:\Windows\Temporary Internet Files 폴더에 있는 쿠키의 복사본입니다. 익스플로러는 쿠키 하나를 하나의 텍스트 파일에 담고 있습니다. 이러한 쿠키 파일을 관리할 수 있는 index.dat라는 파일이 별개로 존재합니다.
예를 들면 C:\Windoes\Cookies 디렉토리를 보면 아래와 같은 쿠키파일들이 있습니다.
C:\Windows\Cookies\hwooky@ad.shinbiro[2].txt
C:\Windows\Cookies\hwooky@adsquare.co[2].txt
C:\Windows\Cookies\hwooky@flycast[1].txt
C:\Windows\Cookies\hwooky@google[1].txt
C:\Windows\Cookies\hwooky@cookie[1].txt
쿠키 파일의 내용을 보면 아래와 같습니다. 첫번째줄과 두번째줄이 각각 쿠키명과 쿠키값을 의미합니다. 나머지는 여러분이 분석해 보세요. 저도 잘 모름.
ID <- 쿠키명
6 <- 쿠키값
www.phpclass.com/example/cookie/
0
3375109376
29397019
118715040
29397010
*
받은 쿠키 보기
넷스케이프 네비게이터 4.0
넷스에서는 쿠키를 볼 수 있는 기능을 별도로 제공하고 있지 않습니다. 따라서 그 내용을 보기 위해서는 직접 쿠키 파일을 텍스트 편집기에서 보면 됩니다. 이러한 쿠키 파일은 보통 "C:\Programs Files\Netscape\Users\Default\cookies.txt"에 있습니다.
인터넷 익스플로러 4.0, 5.0
익스는 브라우저에서 받은 쿠키 파일 리스트를 확인할 수 있습니다. 그러나 파일 리스트만 볼 수 있지 그 내용을 확인할 수는 없습니다. 내용을 보기 위해서는 넷스에서와 같이 텍스트 편집기를 이용하여야 합니다.
***익스 4.0***

작업 표시줄에서
1. 보기를 클릭한 다음
2. 인터넷 옵션을 선택합니다.
3. 일반 탭(기본 탭)에서
4. 설정을 클릭한 다음
5. 파일 보기를 선택합니다.
***익스 5.0***

작업 표시줄에서
1. 도구를 클릭한 다음
2. 인터넷 옵션을 선택합니다.
3. 일반 탭(기본 탭)에서
4. 설정을 클릭한 다음
5. 파일 보기를 선택합니다.
쿠키파일 지우기
넷스에서 쿠키 파일을 지우려면 사용자가 직접 "C:\Programs Files\Netscape\Users\<사용자명>" 폴더 안에 있는 cookies.txt 파일을 찾아서 파일 자체를 지우거나 편집을 해야 합니다.
익스에서 쿠키 파일을 지우려고 할 때, C:\Windows\Cookies 폴더에 있는 쿠키 파일을 지워서는 소용없고 C:\Windows\Temporary Internet Files 폴더에 있는 원본을 직접 지워야 합니다. 지울 때는 현재 동작하고 있는 브라우저를 종료한 다음에 작업하시는 것이 좋습니다. 현 브라우저가 쿠키를 임시 저장하고 있어서 이 정보가 쿠키 파일을 지운 후에 새롭게 쿠키 파일에 저장될 수 있습니다.

'phpsource > 캐시&세션&쿠키' 카테고리의 다른 글

{쿠커}6.쿠키 다루기  (0) 2001.02.20
{쿠커}5.쿠키 규격  (0) 2001.02.20
{쿠커}3.보안  (0) 2001.02.20
{쿠커}2.웹페이지 상태유지  (0) 2001.02.20
{쿠커}1.쿠키란?  (0) 2001.02.20
Posted by 방글24
쿠키 보안성
쿠키는 쿠키를 생성한 서버 또는 쿠키를 받도록 허용된 서버로만 전송됩니다. 이를 위해 서버가 쿠키를 설정할 때에는 그 쿠키가 전송되는 서버의 범위를 제한하게 됩니다.
그러나 쿠키는 각 페이지간 상태 유지를 위해 설계된 것이지 사용자 인증과 같은 애플리케이션을 위해 설계된 것이 아니기 때문에 회원인증 정보 또는 주민등록번호, 카드번호와 같은 사용자 정보를 쿠키에 저장하는 것은 매우 위험한 것 같습니다. 쿠키 파일은 로컬시스템을 사용하는 누구나 접근할 수 있습니다. 파일에 저장되지 않은 상태에서도 원서버(original server)을 가장한 스푸핑 서버(spoofing server)에 의해 쿠키의 내용이 수정될 수도 있다고 합니다. 아래에는 쿠키 보안에 관련된 문서를 링크시켜 놓았으니 쿠키를 이용하기 전에 충분히 살펴보시기 바랍니다.
쿠키 보안에 관련된 자료
  • 쿠키와 프라이버시
    목차 : 프롤로그/여러분의 쿠키는 안녕하신가?/쿠키는 왜 만들었나?/쿠키는 믿을만한가?/해결방법은 없나?
  • Cookie sniffing
    목차 : 개요/현황/취약점 발생원인/해킹 기법/모의 실험/보안 권고
  • 국내 인터넷 서비스 제공업체 보안 취약성 분석 보고서
    목차 : 개요/현황/웹 인증 방식 소개/모의 구축 모델/사례연구(취약점 분석)/실제 모의 사례/보안 권고/취약점 분석(CASE TEST)/결론/관련자료
  • 악성코드에 의한 HTTP Cookie 유출 문제점 및 대책
    목차 : 설명/해결책
  • 쿠키 및 세션을 이용한 인증의 보안 취약성 경고
    목차 : 들어가기에 앞서/PHP에서 쿠키를 이용한 인증의 위험 (PHP에서 GET 방식을 이용한 쿠키 스푸핑)/헤더 조작을 통한 cookie spoofing/쿠키 변수 이름 알아내기/쿠키 인증에 대한 다른 아이디어들/Cookie 인증의 대안, Session/Session spoofing/Session sniffing/Session의 한계를 넘어/글을 마치며
(수정:2010.1.11) 관련정보에 대한 홈페이지 링크가 너무 오래되어 연결되지 않아 삭제합니다.
쿠키 보안 대책
위에서 링크한 자료들을 종합하여 보면 웹사이트 개발자나 사용자가 쿠키를 사용할 때는 아래와 같은 점에 유념하시는 것이 바람직할 것 같습니다. 위에 링크된 자료를 살펴보면 "쿠키 기반의 회원 인증 시스템"을 모델링해 놓은 예제가 있으니 이 부분도 꼭 살펴보시기 바랍니다.
쿠키인증 기법을 사용하는 사이트의 보안대책
① http://www.netscape.com/newsref/std/cookie_spec.html 사이트의 쿠키 스팩을 따릅니다. 특히, 쿠키 저장시 타인이 임의로 쿠키를 읽어들일 수 없도록 도메인과 경로 지정에 유의합니다. 쿠키들은 쿠키를 받도록 허용된 서버로만 전송됩니다. 서버가 쿠키를 설정할 때 도메인을 지정하면 그 쿠키가 전송되는 서버의 범위를 제한할 수 있습니다. 경로 설정값을 이용하면 쿠키가 전송되는 서버를 제한할 수 있을 뿐만아니라 서버 내의 경로를 제한할 수도 있습니다. 쿠키의 경로를 지정하면 지정된 경로 및 그 하위 경로에 있는 웹문서로만 쿠키가 전달됩니다. 쿠키의 경로를 "/"로 지정하면 해당 서버의 모든 경로에 대하여 쿠키를 전달하기 때문에 가능하면 "/"를 지정하지 말고 특정 디렉토리를 지정하여 사용하기 바랍니다.
② 쿠키에 들어가는 정보는 가능하면 암호화하여 저장합니다. 만약 패스워드 부분을 사용하게 된다면 반드시 암호화하여 저장합니다.
③ 가능하면 쿠키에 지정하는 값을 최소화합니다. 쿠키 정보만 가지고도 개인 정보를 알 수 있는 부분은 피합니다.
④ 개인 정보 열람 및 수정 페이지는 패스워드나 유일한 사용자의 정보를 재입력해야만 들어갈 수 있게 구축합니다. 만약 도용을 당하더라도 개인 패스워드 등 사용자 정보를 입력하게 함으로써 개인의 정보 열람 및 수정을 불가능하게 합니다.
⑤ 도메인과 경로지정에 따라 차이가 있을 수 있으나 대부분 쿠키 정보는 그것을 제공한 사이트에서만 검색할 수 있으므로 검증되지 않은 사용자용 홈페이지는 인증서버와 다른 도메인에 위치시킴으로써 쿠키정보의 유출을 막을 수 있습니다. 즉, 홈페이지 보안을 위해 사용자용 홈페이지는 별도의 도메인으로 서비스합니다.
⑥ 웹메일 보안을 위해 수신된 웹메일의 본문에 첨부되는 HTML 가능 자료의 스크립트 검사를 하거나, 첨부되는 자료는 다른 도메인 사용을 권장합니다.
⑦ 게시판 제목, 본문에는 스크립트 언어의 사용을 금지시키도록 합니다.
⑧ 일반 사용자가 업로드할 수 있는 컨텐츠 부분에는 쿠키 사용을 억제합니다.
⑨ 개인 정보 열람이 가능한 도메인은 분리하거나 인증 서버를 달리합니다.
일반 사용자들의 보안대책
쿠키를 전혀 사용하지 못하도록 브라우저를 설정하면 쿠키 보안을 걱정할 필요가 없겠지만 많은 웹사이트가 쿠키를 전제로 작성되어 있는 현실에서 이는 받아들이기 어려울 것입니다. 쿠키를 사용한다는 것을 전제로 보안 대책을 살펴보면 아래와 같습니다.
① 웹메일 서비스 옵션에서 '자바스크립트 허용여부' 등을 선택할 수 있다면 허용하지 않는 것으로 설정합니다.
② 로그인한 상태로 타인의 홈페이지를 방문하지 않습니다.
③ 쿠키를 받아들이기 전에 주의를 촉구하도록 세팅할 수 있습니다. 그러나 매번 쿠키를 받을 때마다 이에 응답한다는 것은 웹서핑하는데 많은 불편을 가져오게 될 것입니다.
④ 쿠키는 받아들이되 민감한 정보는 결코 입력하지 않습니다. 주민등록번호, 신용카드번호를 입력받는 페이지가 이러한 정보를 쿠키에 저장할 수도 있습니다. 그러니 이러한 정보는 어떠한 경우에도(?) 입력하지 않는 것이 좋겠지요.
대안으로서의 세션
쿠키를 이용한 인증은 어떠한 경우에도 완벽하지 않기 때문에 중요한 정보는 서버에 저장하고 쿠키와 서버의 정보를 비교하여 사용자 인증을 수행하는 것이 좋습니다. 그러나 이러한 방식으로 동작하는 세션의 경우도 주의를 기울이지 않으면 항상 문제가 될 수 있습니다. "쿠키 및 세션을 이용한 인증의 보안 취약성 경고" 문서를 참조바랍니다.
쿠키의 위험성
쿠키에 담긴 내용(신용카드번호와 같은)때문에 쿠키의 위험성을 논하는 것이지 단순한 텍스트 문서로 되어 있는 쿠키가 여러분의 로컬시스템에 바이러스를 심거나 하드디스크를 날려버리지도 않습니다. 단지 그 정보를 서버로 전송할 수 있을 뿐입니다.
PC방에서와 같이 여러사람이 같이 사용하는 로컬시스템에서는 이전 사람이 쿠키에 저장된 정보를 완벽하게 삭제하지 못하면 다음 사람이 이전 사람의 쿠키 정보를 볼 수도 있고, 앞사람과 동일 웹사이트를 접속할 때는 앞사람이 로그인한 상태에서 회원 페이지를 그대로(새로이 로그인 없이도) 볼 수 있으며, 사용자 정보를 브라우저에 그대로 보여 줄 수 있습니다.
쿠키 관리
쿠키는 웹을 좀 더 편리하게 사용할 수 있도록 해주기는 하지만 여러 사람이 같이 사용하는 로컬시스템이 경우에는 있을 지도 모르는 개인 정보를 담고 있는 쿠키를 적절히 관리하는 것은 중요할 것입니다. 쿠키 기반의 웹페이지를 서핑한 후에는 이러한 쿠키 파일을 직접 지울 수도 있고 아니면 쿠키를 관리해 주는 소프트웨어를 이용하여 지울 수도 있습니다.
직접 쿠키 파일을 지우는 방법
웹브라우저에서는 쿠키를 지울 수 있는 기능을 제공하지 않기 때문에 쿠키 파일을 직접 찾아 지워야 합니다. 자세한 것은 다음장 "브라우저 설정"을 참조바랍니다.
쿠키 관리 소프트웨어
직접 쿠키 파일을 지우는 방법은 불편합니다. 쿠키 관리 소프트웨어를 사용하면 저장된 쿠키를 읽고, 삭제하는 작업을 손쉽게 할 수 있으며 웹사이트에 따라 쿠키를 선택적으로 허용할 수 있습니다.
  • Complete Cleanup
    설명 : 하드디스크에 저장된 쿠키, 캐시 등을 지워주는 유틸리티입니다.
  • Cookie Cruncher
    설명 : 쿠키 크런처는 자신의 PC에 내장돼 있는 인터넷 쿠키를 모두 찾아주고, 텍스트 파일 형태로 내역을 볼 수 있고, 삭제할 수 있습니다.
  • Cookie Pal
    설명 : 쿠키 정보를 이용하는 웹사이트를 미리 지정해 접속과 함께 자동으로 쿠키를 차단하거나 읽어들이도록 하는 옵션 기능을 갖고 있습니다.
  • IEClean
    설명 : IE가 숨김파일(히든파일)로 지정해 놓고 있는 히스토리 폴더와 쿠키 폴더, 캐시 폴더의 파일들을 찾아서 보여 주며 삭제할 수 있습니다.
  • NSClean
    설명 : NS가 숨김파일(히든파일)로 지정해 놓고 있는 히스토리 폴더와 쿠키 폴더, 캐시 폴더의 파일들을 찾아서 보여 주며 삭제할 수 있습니다.
  • Cookie Crusher
    설명 : 웹 사이트에 따라 쿠키를 받아들이거나 거부하는 것을 도와주는 도구입니다.
  • Cache and Cookie Washer
    설명 : 쿠키 뿐만 아니라 캐시, 히스토리, Drop Down Address Bar, Auto Complete Data forms 등 인터넷을 사용하면서 생긴 모든 흔적을 찾아서 지워주는 도구입니다.
(수정:2010.1.11) 관련정보에 대한 홈페이지 링크가 너무 오래되어 연결되지 않아 삭제합니다.

'phpsource > 캐시&세션&쿠키' 카테고리의 다른 글

{쿠커}5.쿠키 규격  (0) 2001.02.20
{쿠커}4.브라우저 설정  (0) 2001.02.20
{쿠커}2.웹페이지 상태유지  (0) 2001.02.20
{쿠커}1.쿠키란?  (0) 2001.02.20
{세션핸들러}3.업그레이드 및 패치  (0) 2001.02.02
Posted by 방글24
상태 유지
메뉴 "회원인증에 대하여"의 세션관리에서도 언급하였듯이 인터넷의 기본 프로토콜인 HTTP(HyperText Transfer Protocol)를 사용하면, 웹 페이지에 대한 각각의 요구(request)은 다른 요구들과 상관 관계없이 모두 독립적입니다. 즉, 현재 페이지에 대한 데이터를 모두 수신하게 되면 웹서버는 현재 접속된 브라우저에 대하여 자동으로 세션이 종료합니다. 다음에는 웹브라우저에서 모든 것이 처리되기 때문에 웹서버와의 관계는 완전히 끊어지게 됩니다. 즉, 웹서버와 웹브라우저는 파일 단위의 요구, 연결, 송수신을 기본으로 하고 있습니다. 그렇기 때문에 웹서버는 그 방문자에게 이전에 어떠한 페이지가 보내어졌는지에 관한 아무런 기록도 가지고 있지 않습니다. 이런 프로토콜을 스테이트리스 프로토콜(stateless protocol)이라고 합니다.
그러나 대부분의 웹문서는 페이지간 변수의 값을 보존하여야 하는 경우가 많이 발생하게되어 상태 유지 관리가 필요하게 됩니다. 이러한 상태를 유지하기 위한 방법으로는 다음과 같은 것이 있습니다.
▷쿠키 사용
▷URL 링크에 암호화해서 넣기
▷히든 태그 사용
▷다른 프레임에 저장하기
▷웹서버에 저장하기
그전에는 이러한 상태 유지를 위해 URL 파라미터 또는 히든 태그(hidden type)를 이용하였으나 이러한 방법에 의한 상태 유지는 사용자가 연결을 유지하고 있는 동안의 단기간 지속할 뿐입니다. 연결이 끊어지게 되면 상태 유지가 종료하게 됩니다. 또한 각 페이지간에 정보를 넘겨주기 위해서 매 페이지마다 히든 태그(<INPUT type=hidden ......>)를 사용하게 되면 소스 구조가 대단히 지저분해지게 됩니다.
쿠키에 의한 상태유지
이러한 지속적인 상태 유지 문제(HTTP의 스테이트리스 문제)를 해결하고자 넷스케이프에서 쿠키라는 상태 정보 유지 시스템을 만들어 사용하던 것으로 지금은 익스플로러 또는 모자이크 등 대부분의 웹브라우저에서 널리 사용되고 있습니다. 쿠키를 이용하게 되면 서버와 브라우저가 지속적으로 정보를 주고 받을 수 있으며 이를 통해 어떤 상태를 지속적으로 유지할 수 있게 되는 것입니다.
상태를 유지한다는 말은 사용자가 같은 웹 사이트 내에서 서로 다른 페이지로 옮겨 다니는 상황에서 여러 정보들을 기억한다는 것입니다. 이러한 정보를 가지고 있으면 사용자 설정, 초기 폼 값 채우기, 방문 횟수의 기억과 같은 많은 일들을 수행할 수 있으며 페이지를 사용할 때 더 많은 정보를 사용자에게 제공할 수 있습니다.
쿠키는 웹사이트에서 상태를 관리할 수 있는 가장 강력한 방법 중 하나입니다.

'phpsource > 캐시&세션&쿠키' 카테고리의 다른 글

{쿠커}4.브라우저 설정  (0) 2001.02.20
{쿠커}3.보안  (0) 2001.02.20
{쿠커}1.쿠키란?  (0) 2001.02.20
{세션핸들러}3.업그레이드 및 패치  (0) 2001.02.02
{세션핸들러}2.사용방법  (0) 2001.02.02
Posted by 방글24